diff options
Diffstat (limited to 'lldb/source/Plugins/ExpressionParser')
51 files changed, 3969 insertions, 1627 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 77bb9544ea40..39ba5f4e9e4f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -1,4 +1,4 @@ -//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===// +//===-- ASTResultSynthesizer.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,10 +8,10 @@ #include "ASTResultSynthesizer.h" +#include "ClangASTImporter.h" #include "ClangPersistentVariables.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" @@ -248,48 +248,37 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, // For Lvalues // // - In AST result synthesis (here!) the expression E is transformed into an - // initialization - // T *$__lldb_expr_result_ptr = &E. + // initialization T *$__lldb_expr_result_ptr = &E. // // - In structure allocation, a pointer-sized slot is allocated in the - // struct that is to be - // passed into the expression. + // struct that is to be passed into the expression. // // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are - // redirected at - // an entry in the struct ($__lldb_arg) passed into the expression. - // (Other persistent - // variables are treated similarly, having been materialized as - // references, but in those - // cases the value of the reference itself is never modified.) + // redirected at an entry in the struct ($__lldb_arg) passed into the + // expression. (Other persistent variables are treated similarly, having + // been materialized as references, but in those cases the value of the + // reference itself is never modified.) // // - During materialization, $0 (the result persistent variable) is ignored. // // - During dematerialization, $0 is marked up as a load address with value - // equal to the - // contents of the structure entry. + // equal to the contents of the structure entry. // // For Rvalues // // - In AST result synthesis the expression E is transformed into an - // initialization - // static T $__lldb_expr_result = E. + // initialization static T $__lldb_expr_result = E. // // - In structure allocation, a pointer-sized slot is allocated in the - // struct that is to be - // passed into the expression. + // struct that is to be passed into the expression. // // - In IR transformations, an instruction is inserted at the beginning of - // the function to - // dereference the pointer resident in the slot. Reads and writes to - // $__lldb_expr_result - // are redirected at that dereferenced version. Guard variables for the - // static variable - // are excised. + // the function to dereference the pointer resident in the slot. Reads and + // writes to $__lldb_expr_result are redirected at that dereferenced + // version. Guard variables for the static variable are excised. // // - During materialization, $0 (the result persistent variable) is - // populated with the location - // of a newly-allocated area of memory. + // populated with the location of a newly-allocated area of memory. // // - During dematerialization, $0 is ignored. @@ -325,7 +314,8 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body, else result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr"); - m_sema->RequireCompleteType(SourceLocation(), expr_qual_type, + m_sema->RequireCompleteType(last_expr->getSourceRange().getBegin(), + expr_qual_type, clang::diag::err_incomplete_type); QualType ptr_qual_type; @@ -453,13 +443,13 @@ void ASTResultSynthesizer::CommitPersistentDecls() { return; auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); - ClangASTContext *scratch_ctx = ClangASTContext::GetScratch(m_target); + TypeSystemClang *scratch_ctx = TypeSystemClang::GetScratch(m_target); for (clang::NamedDecl *decl : m_decls) { StringRef name = decl->getName(); ConstString name_cs(name.str().c_str()); - Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl( + Decl *D_scratch = persistent_vars->GetClangASTImporter()->DeportDecl( &scratch_ctx->getASTContext(), decl); if (!D_scratch) { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h index 0b0f3b97705d..9de823bc75a7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h @@ -6,13 +6,20 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ASTResultSynthesizer_h_ -#define liblldb_ASTResultSynthesizer_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H -#include "lldb/Core/ClangForward.h" #include "lldb/Target/Target.h" #include "clang/Sema/SemaConsumer.h" +namespace clang { +class CompoundStmt; +class DeclContext; +class NamedDecl; +class ObjCMethodDecl; +class TypeDecl; +} // namespace clang + namespace lldb_private { /// \class ASTResultSynthesizer ASTResultSynthesizer.h @@ -163,4 +170,4 @@ private: } // namespace lldb_private -#endif // liblldb_ASTResultSynthesizer_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTRESULTSYNTHESIZER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index a164d48ae3e0..40f0de40da52 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -1,4 +1,4 @@ -//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===// +//===-- ASTStructExtractor.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h index 078cf095975f..c285f6408895 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h @@ -6,13 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ASTStructExtractor_h_ -#define liblldb_ASTStructExtractor_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H #include "ClangExpressionVariable.h" #include "ClangFunctionCaller.h" -#include "lldb/Core/ClangForward.h" #include "clang/Sema/SemaConsumer.h" namespace lldb_private { @@ -129,4 +128,4 @@ private: } // namespace lldb_private -#endif // liblldb_ASTStructExtractor_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTSTRUCTEXTRACTOR_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp index bbdf4e31c5a4..1e438ed9d73e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp @@ -1,4 +1,4 @@ -//===-- ASTUtils.cpp --------------------------------------------*- C++ -*-===// +//===-- ASTUtils.cpp ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index d429e8c3855f..3787c572d45b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -6,9 +6,10 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ASTUtils_h_ -#define liblldb_ASTUtils_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H +#include "clang/Basic/Module.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/Sema.h" @@ -71,7 +72,7 @@ public: return m_Source->getModule(ID); } - llvm::Optional<ASTSourceDescriptor> + llvm::Optional<clang::ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override { return m_Source->getSourceDescriptor(ID); } @@ -576,4 +577,4 @@ public: }; } // namespace lldb_private -#endif // liblldb_ASTUtils_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp new file mode 100644 index 000000000000..ac16738933ac --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -0,0 +1,1212 @@ +//===-- ClangASTImporter.cpp ----------------------------------------------===// +// +// 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/Core/Module.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" +#include "llvm/Support/raw_ostream.h" + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangASTSource.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +#include <memory> + +using namespace lldb_private; +using namespace clang; + +CompilerType ClangASTImporter::CopyType(TypeSystemClang &dst_ast, + const CompilerType &src_type) { + clang::ASTContext &dst_clang_ast = dst_ast.getASTContext(); + + TypeSystemClang *src_ast = + llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem()); + if (!src_ast) + return CompilerType(); + + clang::ASTContext &src_clang_ast = src_ast->getASTContext(); + + clang::QualType src_qual_type = ClangUtil::GetQualType(src_type); + + ImporterDelegateSP delegate_sp(GetDelegate(&dst_clang_ast, &src_clang_ast)); + if (!delegate_sp) + return CompilerType(); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, &dst_clang_ast); + + llvm::Expected<QualType> ret_or_error = delegate_sp->Import(src_qual_type); + if (!ret_or_error) { + Log *log = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG_ERROR(log, ret_or_error.takeError(), + "Couldn't import type: {0}"); + return CompilerType(); + } + + lldb::opaque_compiler_type_t dst_clang_type = ret_or_error->getAsOpaquePtr(); + + if (dst_clang_type) + return CompilerType(&dst_ast, dst_clang_type); + return CompilerType(); +} + +clang::Decl *ClangASTImporter::CopyDecl(clang::ASTContext *dst_ast, + clang::Decl *decl) { + ImporterDelegateSP delegate_sp; + + clang::ASTContext *src_ast = &decl->getASTContext(); + delegate_sp = GetDelegate(dst_ast, src_ast); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, dst_ast); + + if (!delegate_sp) + return nullptr; + + llvm::Expected<clang::Decl *> result = delegate_sp->Import(decl); + if (!result) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + LLDB_LOG_ERROR(log, result.takeError(), "Couldn't import decl: {0}"); + if (log) { + lldb::user_id_t user_id = LLDB_INVALID_UID; + ClangASTMetadata *metadata = GetDeclMetadata(decl); + if (metadata) + user_id = metadata->GetUserID(); + + if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl)) + LLDB_LOG(log, + " [ClangASTImporter] WARNING: Failed to import a {0} " + "'{1}', metadata {2}", + decl->getDeclKindName(), named_decl->getNameAsString(), + user_id); + else + LLDB_LOG(log, + " [ClangASTImporter] WARNING: Failed to import a {0}, " + "metadata {1}", + decl->getDeclKindName(), user_id); + } + return nullptr; + } + + return *result; +} + +class DeclContextOverride { +private: + struct Backup { + clang::DeclContext *decl_context; + clang::DeclContext *lexical_decl_context; + }; + + llvm::DenseMap<clang::Decl *, Backup> m_backups; + + void OverrideOne(clang::Decl *decl) { + if (m_backups.find(decl) != m_backups.end()) { + return; + } + + m_backups[decl] = {decl->getDeclContext(), decl->getLexicalDeclContext()}; + + decl->setDeclContext(decl->getASTContext().getTranslationUnitDecl()); + decl->setLexicalDeclContext(decl->getASTContext().getTranslationUnitDecl()); + } + + bool ChainPassesThrough( + clang::Decl *decl, clang::DeclContext *base, + clang::DeclContext *(clang::Decl::*contextFromDecl)(), + clang::DeclContext *(clang::DeclContext::*contextFromContext)()) { + for (DeclContext *decl_ctx = (decl->*contextFromDecl)(); decl_ctx; + decl_ctx = (decl_ctx->*contextFromContext)()) { + if (decl_ctx == base) { + return true; + } + } + + return false; + } + + clang::Decl *GetEscapedChild(clang::Decl *decl, + clang::DeclContext *base = nullptr) { + if (base) { + // decl's DeclContext chains must pass through base. + + if (!ChainPassesThrough(decl, base, &clang::Decl::getDeclContext, + &clang::DeclContext::getParent) || + !ChainPassesThrough(decl, base, &clang::Decl::getLexicalDeclContext, + &clang::DeclContext::getLexicalParent)) { + return decl; + } + } else { + base = clang::dyn_cast<clang::DeclContext>(decl); + + if (!base) { + return nullptr; + } + } + + if (clang::DeclContext *context = + clang::dyn_cast<clang::DeclContext>(decl)) { + for (clang::Decl *decl : context->decls()) { + if (clang::Decl *escaped_child = GetEscapedChild(decl)) { + return escaped_child; + } + } + } + + return nullptr; + } + + void Override(clang::Decl *decl) { + if (clang::Decl *escaped_child = GetEscapedChild(decl)) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, + " [ClangASTImporter] DeclContextOverride couldn't " + "override ({0}Decl*){1} - its child ({2}Decl*){3} escapes", + decl->getDeclKindName(), decl, escaped_child->getDeclKindName(), + escaped_child); + lldbassert(0 && "Couldn't override!"); + } + + OverrideOne(decl); + } + +public: + DeclContextOverride() {} + + void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) { + for (DeclContext *decl_context = decl->getLexicalDeclContext(); + decl_context; decl_context = decl_context->getLexicalParent()) { + DeclContext *redecl_context = decl_context->getRedeclContext(); + + if (llvm::isa<FunctionDecl>(redecl_context) && + llvm::isa<TranslationUnitDecl>(redecl_context->getLexicalParent())) { + for (clang::Decl *child_decl : decl_context->decls()) { + Override(child_decl); + } + } + } + } + + ~DeclContextOverride() { + for (const std::pair<clang::Decl *, Backup> &backup : m_backups) { + backup.first->setDeclContext(backup.second.decl_context); + backup.first->setLexicalDeclContext(backup.second.lexical_decl_context); + } + } +}; + +namespace { +/// Completes all imported TagDecls at the end of the scope. +/// +/// While in a CompleteTagDeclsScope, every decl that could be completed will +/// be completed at the end of the scope (including all Decls that are +/// imported while completing the original Decls). +class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { + ClangASTImporter::ImporterDelegateSP m_delegate; + llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete; + llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed; + clang::ASTContext *m_dst_ctx; + clang::ASTContext *m_src_ctx; + ClangASTImporter &importer; + +public: + /// Constructs a CompleteTagDeclsScope. + /// \param importer The ClangASTImporter that we should observe. + /// \param dst_ctx The ASTContext to which Decls are imported. + /// \param src_ctx The ASTContext from which Decls are imported. + explicit CompleteTagDeclsScope(ClangASTImporter &importer, + clang::ASTContext *dst_ctx, + clang::ASTContext *src_ctx) + : m_delegate(importer.GetDelegate(dst_ctx, src_ctx)), m_dst_ctx(dst_ctx), + m_src_ctx(src_ctx), importer(importer) { + m_delegate->SetImportListener(this); + } + + virtual ~CompleteTagDeclsScope() { + ClangASTImporter::ASTContextMetadataSP to_context_md = + importer.GetContextMetadata(m_dst_ctx); + + // Complete all decls we collected until now. + while (!m_decls_to_complete.empty()) { + NamedDecl *decl = m_decls_to_complete.pop_back_val(); + m_decls_already_completed.insert(decl); + + // We should only complete decls coming from the source context. + assert(to_context_md->m_origins[decl].ctx == m_src_ctx); + + Decl *original_decl = to_context_md->m_origins[decl].decl; + + // Complete the decl now. + TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); + if (auto *tag_decl = dyn_cast<TagDecl>(decl)) { + if (auto *original_tag_decl = dyn_cast<TagDecl>(original_decl)) { + if (original_tag_decl->isCompleteDefinition()) { + m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl); + tag_decl->setCompleteDefinition(true); + } + } + + tag_decl->setHasExternalLexicalStorage(false); + tag_decl->setHasExternalVisibleStorage(false); + } else if (auto *container_decl = dyn_cast<ObjCContainerDecl>(decl)) { + container_decl->setHasExternalLexicalStorage(false); + container_decl->setHasExternalVisibleStorage(false); + } + + to_context_md->m_origins.erase(decl); + } + + // Stop listening to imported decls. We do this after clearing the + // Decls we needed to import to catch all Decls they might have pulled in. + m_delegate->RemoveImportListener(); + } + + void NewDeclImported(clang::Decl *from, clang::Decl *to) override { + // Filter out decls that we can't complete later. + if (!isa<TagDecl>(to) && !isa<ObjCInterfaceDecl>(to)) + return; + RecordDecl *from_record_decl = dyn_cast<RecordDecl>(from); + // We don't need to complete injected class name decls. + if (from_record_decl && from_record_decl->isInjectedClassName()) + return; + + NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to); + // Check if we already completed this type. + if (m_decls_already_completed.count(to_named_decl) != 0) + return; + m_decls_to_complete.push_back(to_named_decl); + } +}; +} // namespace + +CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst, + const CompilerType &src_type) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + TypeSystemClang *src_ctxt = + llvm::cast<TypeSystemClang>(src_type.GetTypeSystem()); + + LLDB_LOG(log, + " [ClangASTImporter] DeportType called on ({0}Type*){1} " + "from (ASTContext*){2} to (ASTContext*){3}", + src_type.GetTypeName(), src_type.GetOpaqueQualType(), + &src_ctxt->getASTContext(), &dst.getASTContext()); + + DeclContextOverride decl_context_override; + + if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>()) + decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl()); + + CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(), + &src_ctxt->getASTContext()); + return CopyType(dst, src_type); +} + +clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, + clang::Decl *decl) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + clang::ASTContext *src_ctx = &decl->getASTContext(); + LLDB_LOG(log, + " [ClangASTImporter] DeportDecl called on ({0}Decl*){1} from " + "(ASTContext*){2} to (ASTContext*){3}", + decl->getDeclKindName(), decl, src_ctx, dst_ctx); + + DeclContextOverride decl_context_override; + + decl_context_override.OverrideAllDeclsFromContainingFunction(decl); + + clang::Decl *result; + { + CompleteTagDeclsScope complete_scope(*this, dst_ctx, src_ctx); + result = CopyDecl(dst_ctx, decl); + } + + if (!result) + return nullptr; + + LLDB_LOG(log, + " [ClangASTImporter] DeportDecl deported ({0}Decl*){1} to " + "({2}Decl*){3}", + decl->getDeclKindName(), decl, result->getDeclKindName(), result); + + return result; +} + +bool ClangASTImporter::CanImport(const CompilerType &type) { + if (!ClangUtil::IsClangType(type)) + return false; + + // TODO: remove external completion BOOL + // CompleteAndFetchChildren should get the Decl out and check for the + + clang::QualType qual_type( + ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + if (GetDeclOrigin(cxx_record_decl).Valid()) + return true; + } + } break; + + case clang::Type::Enum: { + clang::EnumDecl *enum_decl = + llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) { + if (GetDeclOrigin(enum_decl).Valid()) + return true; + } + } break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added + // ASTContext because it only supports TagDecl objects right now... + if (class_interface_decl) { + if (GetDeclOrigin(class_interface_decl).Valid()) + return true; + } + } + } break; + + case clang::Type::Typedef: + return CanImport(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getUnderlyingType() + .getAsOpaquePtr())); + + case clang::Type::Auto: + return CanImport(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::AutoType>(qual_type) + ->getDeducedType() + .getAsOpaquePtr())); + + case clang::Type::Elaborated: + return CanImport(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::ElaboratedType>(qual_type) + ->getNamedType() + .getAsOpaquePtr())); + + case clang::Type::Paren: + return CanImport(CompilerType( + type.GetTypeSystem(), + llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + break; + } + + return false; +} + +bool ClangASTImporter::Import(const CompilerType &type) { + if (!ClangUtil::IsClangType(type)) + return false; + // TODO: remove external completion BOOL + // CompleteAndFetchChildren should get the Decl out and check for the + + clang::QualType qual_type( + ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) { + case clang::Type::Record: { + const clang::CXXRecordDecl *cxx_record_decl = + qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) { + if (GetDeclOrigin(cxx_record_decl).Valid()) + return CompleteAndFetchChildren(qual_type); + } + } break; + + case clang::Type::Enum: { + clang::EnumDecl *enum_decl = + llvm::cast<clang::EnumType>(qual_type)->getDecl(); + if (enum_decl) { + if (GetDeclOrigin(enum_decl).Valid()) + return CompleteAndFetchChildren(qual_type); + } + } break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: { + const clang::ObjCObjectType *objc_class_type = + llvm::dyn_cast<clang::ObjCObjectType>(qual_type); + if (objc_class_type) { + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added + // ASTContext because it only supports TagDecl objects right now... + if (class_interface_decl) { + if (GetDeclOrigin(class_interface_decl).Valid()) + return CompleteAndFetchChildren(qual_type); + } + } + } break; + + case clang::Type::Typedef: + return Import(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::TypedefType>(qual_type) + ->getDecl() + ->getUnderlyingType() + .getAsOpaquePtr())); + + case clang::Type::Auto: + return Import(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::AutoType>(qual_type) + ->getDeducedType() + .getAsOpaquePtr())); + + case clang::Type::Elaborated: + return Import(CompilerType(type.GetTypeSystem(), + llvm::cast<clang::ElaboratedType>(qual_type) + ->getNamedType() + .getAsOpaquePtr())); + + case clang::Type::Paren: + return Import(CompilerType( + type.GetTypeSystem(), + llvm::cast<clang::ParenType>(qual_type)->desugar().getAsOpaquePtr())); + + default: + break; + } + return false; +} + +bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { + if (!CanImport(compiler_type)) + return false; + + if (Import(compiler_type)) { + TypeSystemClang::CompleteTagDeclarationDefinition(compiler_type); + return true; + } + + TypeSystemClang::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), + false); + return false; +} + +bool ClangASTImporter::LayoutRecordType( + const clang::RecordDecl *record_decl, uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets) { + RecordDeclToLayoutMap::iterator pos = + m_record_decl_to_layout_map.find(record_decl); + bool success = false; + base_offsets.clear(); + vbase_offsets.clear(); + if (pos != m_record_decl_to_layout_map.end()) { + bit_size = pos->second.bit_size; + alignment = pos->second.alignment; + field_offsets.swap(pos->second.field_offsets); + base_offsets.swap(pos->second.base_offsets); + vbase_offsets.swap(pos->second.vbase_offsets); + m_record_decl_to_layout_map.erase(pos); + success = true; + } else { + bit_size = 0; + alignment = 0; + field_offsets.clear(); + } + return success; +} + +void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl, + const LayoutInfo &layout) { + m_record_decl_to_layout_map.insert(std::make_pair(decl, layout)); +} + +bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) { + DeclOrigin decl_origin = GetDeclOrigin(decl); + + if (!decl_origin.Valid()) + return false; + + if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&decl->getASTContext(), decl_origin.ctx)); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, + &decl->getASTContext()); + if (delegate_sp) + delegate_sp->ImportDefinitionTo(decl, decl_origin.decl); + + return true; +} + +bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, + clang::TagDecl *origin_decl) { + clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext(); + + if (!TypeSystemClang::GetCompleteDecl(origin_ast_ctx, origin_decl)) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&decl->getASTContext(), origin_ast_ctx)); + + if (delegate_sp) + delegate_sp->ImportDefinitionTo(decl, origin_decl); + + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + OriginMap &origins = context_md->m_origins; + + origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl); + + return true; +} + +bool ClangASTImporter::CompleteObjCInterfaceDecl( + clang::ObjCInterfaceDecl *interface_decl) { + DeclOrigin decl_origin = GetDeclOrigin(interface_decl); + + if (!decl_origin.Valid()) + return false; + + if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl)) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx)); + + if (delegate_sp) + delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl); + + if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass()) + RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0)); + + return true; +} + +bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) { + if (!RequireCompleteType(type)) + return false; + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + if (const TagType *tag_type = type->getAs<TagType>()) { + TagDecl *tag_decl = tag_type->getDecl(); + + DeclOrigin decl_origin = GetDeclOrigin(tag_decl); + + if (!decl_origin.Valid()) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&tag_decl->getASTContext(), decl_origin.ctx)); + + ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp, + &tag_decl->getASTContext()); + + TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl); + + for (Decl *origin_child_decl : origin_tag_decl->decls()) { + llvm::Expected<Decl *> imported_or_err = + delegate_sp->Import(origin_child_decl); + if (!imported_or_err) { + LLDB_LOG_ERROR(log, imported_or_err.takeError(), + "Couldn't import decl: {0}"); + return false; + } + } + + if (RecordDecl *record_decl = dyn_cast<RecordDecl>(origin_tag_decl)) + record_decl->setHasLoadedFieldsFromExternalStorage(true); + + return true; + } + + if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) { + if (ObjCInterfaceDecl *objc_interface_decl = + objc_object_type->getInterface()) { + DeclOrigin decl_origin = GetDeclOrigin(objc_interface_decl); + + if (!decl_origin.Valid()) + return false; + + ImporterDelegateSP delegate_sp( + GetDelegate(&objc_interface_decl->getASTContext(), decl_origin.ctx)); + + ObjCInterfaceDecl *origin_interface_decl = + llvm::dyn_cast<ObjCInterfaceDecl>(decl_origin.decl); + + for (Decl *origin_child_decl : origin_interface_decl->decls()) { + llvm::Expected<Decl *> imported_or_err = + delegate_sp->Import(origin_child_decl); + if (!imported_or_err) { + LLDB_LOG_ERROR(log, imported_or_err.takeError(), + "Couldn't import decl: {0}"); + return false; + } + } + + return true; + } + return false; + } + + return true; +} + +bool ClangASTImporter::RequireCompleteType(clang::QualType type) { + if (type.isNull()) + return false; + + if (const TagType *tag_type = type->getAs<TagType>()) { + TagDecl *tag_decl = tag_type->getDecl(); + + if (tag_decl->getDefinition() || tag_decl->isBeingDefined()) + return true; + + return CompleteTagDecl(tag_decl); + } + if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>()) { + if (ObjCInterfaceDecl *objc_interface_decl = + objc_object_type->getInterface()) + return CompleteObjCInterfaceDecl(objc_interface_decl); + return false; + } + if (const ArrayType *array_type = type->getAsArrayTypeUnsafe()) + return RequireCompleteType(array_type->getElementType()); + if (const AtomicType *atomic_type = type->getAs<AtomicType>()) + return RequireCompleteType(atomic_type->getPointeeType()); + + return true; +} + +ClangASTMetadata *ClangASTImporter::GetDeclMetadata(const clang::Decl *decl) { + DeclOrigin decl_origin = GetDeclOrigin(decl); + + if (decl_origin.Valid()) { + TypeSystemClang *ast = TypeSystemClang::GetASTContext(decl_origin.ctx); + return ast->GetMetadata(decl_origin.decl); + } + TypeSystemClang *ast = TypeSystemClang::GetASTContext(&decl->getASTContext()); + return ast->GetMetadata(decl); +} + +ClangASTImporter::DeclOrigin +ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + OriginMap &origins = context_md->m_origins; + + OriginMap::iterator iter = origins.find(decl); + + if (iter != origins.end()) + return iter->second; + return DeclOrigin(); +} + +void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, + clang::Decl *original_decl) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + OriginMap &origins = context_md->m_origins; + + OriginMap::iterator iter = origins.find(decl); + + if (iter != origins.end()) { + iter->second.decl = original_decl; + iter->second.ctx = &original_decl->getASTContext(); + return; + } + origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl); +} + +void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, + NamespaceMapSP &namespace_map) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + context_md->m_namespace_maps[decl] = namespace_map; +} + +ClangASTImporter::NamespaceMapSP +ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl) { + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps; + + NamespaceMetaMap::iterator iter = namespace_maps.find(decl); + + if (iter != namespace_maps.end()) + return iter->second; + return NamespaceMapSP(); +} + +void ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl) { + assert(decl); + ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); + + const DeclContext *parent_context = decl->getDeclContext(); + const NamespaceDecl *parent_namespace = + dyn_cast<NamespaceDecl>(parent_context); + NamespaceMapSP parent_map; + + if (parent_namespace) + parent_map = GetNamespaceMap(parent_namespace); + + NamespaceMapSP new_map; + + new_map = std::make_shared<NamespaceMap>(); + + if (context_md->m_map_completer) { + std::string namespace_string = decl->getDeclName().getAsString(); + + context_md->m_map_completer->CompleteNamespaceMap( + new_map, ConstString(namespace_string.c_str()), parent_map); + } + + context_md->m_namespace_maps[decl] = new_map; +} + +void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, + " [ClangASTImporter] Forgetting destination (ASTContext*){0}", + dst_ast); + + m_metadata_map.erase(dst_ast); +} + +void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, + clang::ASTContext *src_ast) { + ASTContextMetadataSP md = MaybeGetContextMetadata(dst_ast); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, + " [ClangASTImporter] Forgetting source->dest " + "(ASTContext*){0}->(ASTContext*){1}", + src_ast, dst_ast); + + if (!md) + return; + + md->m_delegates.erase(src_ast); + + for (OriginMap::iterator iter = md->m_origins.begin(); + iter != md->m_origins.end();) { + if (iter->second.ctx == src_ast) + md->m_origins.erase(iter++); + else + ++iter; + } +} + +ClangASTImporter::MapCompleter::~MapCompleter() { return; } + +llvm::Expected<Decl *> +ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { + if (m_std_handler) { + llvm::Optional<Decl *> D = m_std_handler->Import(From); + if (D) { + // Make sure we don't use this decl later to map it back to it's original + // decl. The decl the CxxModuleHandler created has nothing to do with + // the one from debug info, and linking those two would just cause the + // ASTImporter to try 'updating' the module decl with the minimal one from + // the debug info. + m_decls_to_ignore.insert(*D); + return *D; + } + } + + // Check which ASTContext this declaration originally came from. + DeclOrigin origin = m_master.GetDeclOrigin(From); + // If it originally came from the target ASTContext then we can just + // pretend that the original is the one we imported. This can happen for + // example when inspecting a persistent declaration from the scratch + // ASTContext (which will provide the declaration when parsing the + // expression and then we later try to copy the declaration back to the + // scratch ASTContext to store the result). + // Without this check we would ask the ASTImporter to import a declaration + // into the same ASTContext where it came from (which doesn't make a lot of + // sense). + if (origin.Valid() && origin.ctx == &getToContext()) { + RegisterImportedDecl(From, origin.decl); + return origin.decl; + } + + // This declaration came originally from another ASTContext. Instead of + // copying our potentially incomplete 'From' Decl we instead go to the + // original ASTContext and copy the original to the target. This is not + // only faster than first completing our current decl and then copying it + // to the target, but it also prevents that indirectly copying the same + // declaration to the same target requires the ASTImporter to merge all + // the different decls that appear to come from different ASTContexts (even + // though all these different source ASTContexts just got a copy from + // one source AST). + if (origin.Valid()) { + auto R = m_master.CopyDecl(&getToContext(), origin.decl); + if (R) { + RegisterImportedDecl(From, R); + return R; + } + } + + // If we have a forcefully completed type, try to find an actual definition + // for it in other modules. + const ClangASTMetadata *md = m_master.GetDeclMetadata(From); + auto *td = dyn_cast<TagDecl>(From); + if (td && md && md->IsForcefullyCompleted()) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG(log, + "[ClangASTImporter] Searching for a complete definition of {0} in " + "other modules", + td->getName()); + Expected<DeclContext *> dc_or_err = ImportContext(td->getDeclContext()); + if (!dc_or_err) + return dc_or_err.takeError(); + Expected<DeclarationName> dn_or_err = Import(td->getDeclName()); + if (!dn_or_err) + return dn_or_err.takeError(); + DeclContext *dc = *dc_or_err; + DeclContext::lookup_result lr = dc->lookup(*dn_or_err); + if (lr.size()) { + clang::Decl *lookup_found = lr.front(); + RegisterImportedDecl(From, lookup_found); + m_decls_to_ignore.insert(lookup_found); + return lookup_found; + } else + LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); + } + + return ASTImporter::ImportImpl(From); +} + +void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( + clang::Decl *to, clang::Decl *from) { + // We might have a forward declaration from a shared library that we + // gave external lexical storage so that Clang asks us about the full + // definition when it needs it. In this case the ASTImporter isn't aware + // that the forward decl from the shared library is the actual import + // target but would create a second declaration that would then be defined. + // We want that 'to' is actually complete after this function so let's + // tell the ASTImporter that 'to' was imported from 'from'. + MapImported(from, to); + ASTImporter::Imported(from, to); + + /* + if (to_objc_interface) + to_objc_interface->startDefinition(); + + CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to); + + if (to_cxx_record) + to_cxx_record->startDefinition(); + */ + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + if (llvm::Error err = ImportDefinition(from)) { + LLDB_LOG_ERROR(log, std::move(err), + "[ClangASTImporter] Error during importing definition: {0}"); + return; + } + + if (clang::TagDecl *to_tag = dyn_cast<clang::TagDecl>(to)) { + if (clang::TagDecl *from_tag = dyn_cast<clang::TagDecl>(from)) { + to_tag->setCompleteDefinition(from_tag->isCompleteDefinition()); + + if (Log *log_ast = + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_AST)) { + std::string name_string; + if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) { + llvm::raw_string_ostream name_stream(name_string); + from_named_decl->printName(name_stream); + name_stream.flush(); + } + LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported " + "({1}Decl*){2}, named {3} (from " + "(Decl*){4})", + static_cast<void *>(to->getTranslationUnitDecl()), + from->getDeclKindName(), static_cast<void *>(to), name_string, + static_cast<void *>(from)); + + // Log the AST of the TU. + std::string ast_string; + llvm::raw_string_ostream ast_stream(ast_string); + to->getTranslationUnitDecl()->dump(ast_stream); + LLDB_LOG(log_ast, "{0}", ast_string); + } + } + } + + // If we're dealing with an Objective-C class, ensure that the inheritance + // has been set up correctly. The ASTImporter may not do this correctly if + // the class was originally sourced from symbols. + + if (ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to)) { + do { + ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass(); + + if (to_superclass) + break; // we're not going to override it if it's set + + ObjCInterfaceDecl *from_objc_interface = + dyn_cast<ObjCInterfaceDecl>(from); + + if (!from_objc_interface) + break; + + ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass(); + + if (!from_superclass) + break; + + llvm::Expected<Decl *> imported_from_superclass_decl = + Import(from_superclass); + + if (!imported_from_superclass_decl) { + LLDB_LOG_ERROR(log, imported_from_superclass_decl.takeError(), + "Couldn't import decl: {0}"); + break; + } + + ObjCInterfaceDecl *imported_from_superclass = + dyn_cast<ObjCInterfaceDecl>(*imported_from_superclass_decl); + + if (!imported_from_superclass) + break; + + if (!to_objc_interface->hasDefinition()) + to_objc_interface->startDefinition(); + + to_objc_interface->setSuperClass(m_source_ctx->getTrivialTypeSourceInfo( + m_source_ctx->getObjCInterfaceType(imported_from_superclass))); + } while (false); + } +} + +/// Takes a CXXMethodDecl and completes the return type if necessary. This +/// is currently only necessary for virtual functions with covariant return +/// types where Clang's CodeGen expects that the underlying records are already +/// completed. +static void MaybeCompleteReturnType(ClangASTImporter &importer, + CXXMethodDecl *to_method) { + if (!to_method->isVirtual()) + return; + QualType return_type = to_method->getReturnType(); + if (!return_type->isPointerType() && !return_type->isReferenceType()) + return; + + clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl(); + if (!rd) + return; + if (rd->getDefinition()) + return; + + importer.CompleteTagDecl(rd); +} + +/// Recreate a module with its parents in \p to_source and return its id. +static OptionalClangModuleID +RemapModule(OptionalClangModuleID from_id, + ClangExternalASTSourceCallbacks &from_source, + ClangExternalASTSourceCallbacks &to_source) { + if (!from_id.HasValue()) + return {}; + clang::Module *module = from_source.getModule(from_id.GetValue()); + OptionalClangModuleID parent = RemapModule( + from_source.GetIDForModule(module->Parent), from_source, to_source); + TypeSystemClang &to_ts = to_source.GetTypeSystem(); + return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework, + module->IsExplicit); +} + +void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, + clang::Decl *to) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + // Some decls shouldn't be tracked here because they were not created by + // copying 'from' to 'to'. Just exit early for those. + if (m_decls_to_ignore.count(to)) + return clang::ASTImporter::Imported(from, to); + + // Transfer module ownership information. + auto *from_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>( + getFromContext().getExternalSource()); + // Can also be a ClangASTSourceProxy. + auto *to_source = llvm::dyn_cast_or_null<ClangExternalASTSourceCallbacks>( + getToContext().getExternalSource()); + if (from_source && to_source) { + OptionalClangModuleID from_id(from->getOwningModuleID()); + OptionalClangModuleID to_id = + RemapModule(from_id, *from_source, *to_source); + TypeSystemClang &to_ts = to_source->GetTypeSystem(); + to_ts.SetOwningModule(to, to_id); + } + + lldb::user_id_t user_id = LLDB_INVALID_UID; + ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); + if (metadata) + user_id = metadata->GetUserID(); + + if (log) { + if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from)) { + std::string name_string; + llvm::raw_string_ostream name_stream(name_string); + from_named_decl->printName(name_stream); + name_stream.flush(); + + LLDB_LOG(log, + " [ClangASTImporter] Imported ({0}Decl*){1}, named {2} (from " + "(Decl*){3}), metadata {4}", + from->getDeclKindName(), to, name_string, from, user_id); + } else { + LLDB_LOG(log, + " [ClangASTImporter] Imported ({0}Decl*){1} (from " + "(Decl*){2}), metadata {3}", + from->getDeclKindName(), to, from, user_id); + } + } + + ASTContextMetadataSP to_context_md = + m_master.GetContextMetadata(&to->getASTContext()); + ASTContextMetadataSP from_context_md = + m_master.MaybeGetContextMetadata(m_source_ctx); + + if (from_context_md) { + OriginMap &origins = from_context_md->m_origins; + + OriginMap::iterator origin_iter = origins.find(from); + + if (origin_iter != origins.end()) { + if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || + user_id != LLDB_INVALID_UID) { + if (origin_iter->second.ctx != &to->getASTContext()) + to_context_md->m_origins[to] = origin_iter->second; + } + + ImporterDelegateSP direct_completer = + m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx); + + if (direct_completer.get() != this) + direct_completer->ASTImporter::Imported(origin_iter->second.decl, to); + + LLDB_LOG(log, + " [ClangASTImporter] Propagated origin " + "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " + "(ASTContext*){3}", + origin_iter->second.decl, origin_iter->second.ctx, + &from->getASTContext(), &to->getASTContext()); + } else { + if (m_new_decl_listener) + m_new_decl_listener->NewDeclImported(from, to); + + if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || + user_id != LLDB_INVALID_UID) { + to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + } + + LLDB_LOG(log, + " [ClangASTImporter] Decl has no origin information in " + "(ASTContext*){0}", + &from->getASTContext()); + } + + if (auto *to_namespace = dyn_cast<clang::NamespaceDecl>(to)) { + auto *from_namespace = cast<clang::NamespaceDecl>(from); + + NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps; + + NamespaceMetaMap::iterator namespace_map_iter = + namespace_maps.find(from_namespace); + + if (namespace_map_iter != namespace_maps.end()) + to_context_md->m_namespace_maps[to_namespace] = + namespace_map_iter->second; + } + } else { + to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + + LLDB_LOG(log, + " [ClangASTImporter] Sourced origin " + "(Decl*){0}/(ASTContext*){1} into (ASTContext*){2}", + from, m_source_ctx, &to->getASTContext()); + } + + if (auto *to_tag_decl = dyn_cast<TagDecl>(to)) { + to_tag_decl->setHasExternalLexicalStorage(); + to_tag_decl->getPrimaryContext()->setMustBuildLookupTable(); + auto from_tag_decl = cast<TagDecl>(from); + + LLDB_LOG( + log, + " [ClangASTImporter] To is a TagDecl - attributes {0}{1} [{2}->{3}]", + (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""), + (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"), + (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete")); + } + + if (auto *to_namespace_decl = dyn_cast<NamespaceDecl>(to)) { + m_master.BuildNamespaceMap(to_namespace_decl); + to_namespace_decl->setHasExternalVisibleStorage(); + } + + if (auto *to_container_decl = dyn_cast<ObjCContainerDecl>(to)) { + to_container_decl->setHasExternalLexicalStorage(); + to_container_decl->setHasExternalVisibleStorage(); + + if (log) { + if (ObjCInterfaceDecl *to_interface_decl = + llvm::dyn_cast<ObjCInterfaceDecl>(to_container_decl)) { + LLDB_LOG( + log, + " [ClangASTImporter] To is an ObjCInterfaceDecl - attributes " + "{0}{1}{2}", + (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""), + (to_interface_decl->hasDefinition() ? " HasDefinition" : "")); + } else { + LLDB_LOG( + log, " [ClangASTImporter] To is an {0}Decl - attributes {1}{2}", + ((Decl *)to_container_decl)->getDeclKindName(), + (to_container_decl->hasExternalLexicalStorage() ? " Lexical" : ""), + (to_container_decl->hasExternalVisibleStorage() ? " Visible" : "")); + } + } + } + + if (clang::CXXMethodDecl *to_method = dyn_cast<CXXMethodDecl>(to)) + MaybeCompleteReturnType(m_master, to_method); +} + +clang::Decl * +ClangASTImporter::ASTImporterDelegate::GetOriginalDecl(clang::Decl *To) { + return m_master.GetDeclOrigin(To).decl; +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h new file mode 100644 index 000000000000..6ceec774914b --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -0,0 +1,328 @@ +//===-- ClangASTImporter.h --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H + +#include <map> +#include <memory> +#include <set> +#include <vector> + +#include "clang/AST/ASTImporter.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/CompilerDeclContext.h" +#include "lldb/lldb-types.h" + +#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" + +#include "llvm/ADT/DenseMap.h" + +namespace lldb_private { + +class ClangASTMetadata; +class TypeSystemClang; + +class ClangASTImporter { +public: + struct LayoutInfo { + LayoutInfo() = default; + typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + OffsetMap; + + uint64_t bit_size = 0; + uint64_t alignment = 0; + llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets; + OffsetMap base_offsets; + OffsetMap vbase_offsets; + }; + + ClangASTImporter() + : m_file_manager(clang::FileSystemOptions(), + FileSystem::Instance().GetVirtualFileSystem()) {} + + CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type); + + clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); + + CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type); + + clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); + + /// Sets the layout for the given RecordDecl. The layout will later be + /// used by Clang's during code generation. Not calling this function for + /// a RecordDecl will cause that Clang's codegen tries to layout the + /// record by itself. + /// + /// \param decl The RecordDecl to set the layout for. + /// \param layout The layout for the record. + void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout); + + bool LayoutRecordType( + const clang::RecordDecl *record_decl, uint64_t &bit_size, + uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets); + + bool CanImport(const CompilerType &type); + + bool Import(const CompilerType &type); + + bool CompleteType(const CompilerType &compiler_type); + + bool CompleteTagDecl(clang::TagDecl *decl); + + bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin); + + bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl); + + bool CompleteAndFetchChildren(clang::QualType type); + + bool RequireCompleteType(clang::QualType type); + + void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl); + + ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl); + + // + // Namespace maps + // + + typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem; + typedef std::vector<NamespaceMapItem> NamespaceMap; + typedef std::shared_ptr<NamespaceMap> NamespaceMapSP; + + void RegisterNamespaceMap(const clang::NamespaceDecl *decl, + NamespaceMapSP &namespace_map); + + NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl); + + void BuildNamespaceMap(const clang::NamespaceDecl *decl); + + // + // Completers for maps + // + + class MapCompleter { + public: + virtual ~MapCompleter(); + + virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map, + ConstString name, + NamespaceMapSP &parent_map) const = 0; + }; + + void InstallMapCompleter(clang::ASTContext *dst_ctx, + MapCompleter &completer) { + ASTContextMetadataSP context_md; + ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); + + if (context_md_iter == m_metadata_map.end()) { + context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); + m_metadata_map[dst_ctx] = context_md; + } else { + context_md = context_md_iter->second; + } + + context_md->m_map_completer = &completer; + } + + void ForgetDestination(clang::ASTContext *dst_ctx); + void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx); + + struct DeclOrigin { + DeclOrigin() : ctx(nullptr), decl(nullptr) {} + + DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl) + : ctx(_ctx), decl(_decl) {} + + DeclOrigin(const DeclOrigin &rhs) { + ctx = rhs.ctx; + decl = rhs.decl; + } + + void operator=(const DeclOrigin &rhs) { + ctx = rhs.ctx; + decl = rhs.decl; + } + + bool Valid() { return (ctx != nullptr || decl != nullptr); } + + clang::ASTContext *ctx; + clang::Decl *decl; + }; + + typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; + + /// Listener interface used by the ASTImporterDelegate to inform other code + /// about decls that have been imported the first time. + struct NewDeclListener { + virtual ~NewDeclListener() = default; + /// A decl has been imported for the first time. + virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0; + }; + + /// ASTImporter that intercepts and records the import process of the + /// underlying ASTImporter. + /// + /// This class updates the map from declarations to their original + /// declarations and can record declarations that have been imported in a + /// certain interval. + /// + /// When intercepting a declaration import, the ASTImporterDelegate uses the + /// CxxModuleHandler to replace any missing or malformed declarations with + /// their counterpart from a C++ module. + struct ASTImporterDelegate : public clang::ASTImporter { + ASTImporterDelegate(ClangASTImporter &master, clang::ASTContext *target_ctx, + clang::ASTContext *source_ctx) + : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx, + master.m_file_manager, true /*minimal*/), + m_master(master), m_source_ctx(source_ctx) { + setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal); + } + + /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate + /// and deattaches it at the end of the scope. Supports being used multiple + /// times on the same ASTImporterDelegate instance in nested scopes. + class CxxModuleScope { + /// The handler we attach to the ASTImporterDelegate. + CxxModuleHandler m_handler; + /// The ASTImporterDelegate we are supposed to attach the handler to. + ASTImporterDelegate &m_delegate; + /// True iff we attached the handler to the ASTImporterDelegate. + bool m_valid = false; + + public: + CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx) + : m_delegate(delegate) { + // If the delegate doesn't have a CxxModuleHandler yet, create one + // and attach it. + if (!delegate.m_std_handler) { + m_handler = CxxModuleHandler(delegate, dst_ctx); + m_valid = true; + delegate.m_std_handler = &m_handler; + } + } + ~CxxModuleScope() { + if (m_valid) { + // Make sure no one messed with the handler we placed. + assert(m_delegate.m_std_handler == &m_handler); + m_delegate.m_std_handler = nullptr; + } + } + }; + + void ImportDefinitionTo(clang::Decl *to, clang::Decl *from); + + void Imported(clang::Decl *from, clang::Decl *to) override; + + clang::Decl *GetOriginalDecl(clang::Decl *To) override; + + void SetImportListener(NewDeclListener *listener) { + assert(m_new_decl_listener == nullptr && "Already attached a listener?"); + m_new_decl_listener = listener; + } + void RemoveImportListener() { m_new_decl_listener = nullptr; } + + protected: + llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override; + + private: + /// Decls we should ignore when mapping decls back to their original + /// ASTContext. Used by the CxxModuleHandler to mark declarations that + /// were created from the 'std' C++ module to prevent that the Importer + /// tries to sync them with the broken equivalent in the debug info AST. + llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore; + ClangASTImporter &m_master; + clang::ASTContext *m_source_ctx; + CxxModuleHandler *m_std_handler = nullptr; + /// The currently attached listener. + NewDeclListener *m_new_decl_listener = nullptr; + }; + + typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP; + typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap; + typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP> + NamespaceMetaMap; + + struct ASTContextMetadata { + ASTContextMetadata(clang::ASTContext *dst_ctx) + : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(), + m_map_completer(nullptr) {} + + clang::ASTContext *m_dst_ctx; + DelegateMap m_delegates; + OriginMap m_origins; + + NamespaceMetaMap m_namespace_maps; + MapCompleter *m_map_completer; + }; + + typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; + typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP> + ContextMetadataMap; + + ContextMetadataMap m_metadata_map; + + ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) { + ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); + + if (context_md_iter == m_metadata_map.end()) { + ASTContextMetadataSP context_md = + ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); + m_metadata_map[dst_ctx] = context_md; + return context_md; + } + return context_md_iter->second; + } + + ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) { + ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); + + if (context_md_iter != m_metadata_map.end()) + return context_md_iter->second; + return ASTContextMetadataSP(); + } + + ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx, + clang::ASTContext *src_ctx) { + ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx); + + DelegateMap &delegates = context_md->m_delegates; + DelegateMap::iterator delegate_iter = delegates.find(src_ctx); + + if (delegate_iter == delegates.end()) { + ImporterDelegateSP delegate = + ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx)); + delegates[src_ctx] = delegate; + return delegate; + } + return delegate_iter->second; + } + + DeclOrigin GetDeclOrigin(const clang::Decl *decl); + + clang::FileManager m_file_manager; + typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> + RecordDeclToLayoutMap; + + RecordDeclToLayoutMap m_record_decl_to_layout_map; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp new file mode 100644 index 000000000000..42933c78b027 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp @@ -0,0 +1,35 @@ +//===-- ClangASTMetadata.cpp ----------------------------------------------===// +// +// 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 "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb_private; + +void ClangASTMetadata::Dump(Stream *s) { + lldb::user_id_t uid = GetUserID(); + + if (uid != LLDB_INVALID_UID) { + s->Printf("uid=0x%" PRIx64, uid); + } + + uint64_t isa_ptr = GetISAPtr(); + if (isa_ptr != 0) { + s->Printf("isa_ptr=0x%" PRIx64, isa_ptr); + } + + const char *obj_ptr_name = GetObjectPtrName(); + if (obj_ptr_name) { + s->Printf("obj_ptr_name=\"%s\" ", obj_ptr_name); + } + + if (m_is_dynamic_cxx) { + s->Printf("is_dynamic_cxx=%i ", m_is_dynamic_cxx); + } + s->EOL(); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h new file mode 100644 index 000000000000..d3bcde2ced79 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h @@ -0,0 +1,110 @@ +//===-- ClangASTMetadata.h --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H + +#include "lldb/Core/dwarf.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +namespace lldb_private { + +class ClangASTMetadata { +public: + ClangASTMetadata() + : m_user_id(0), m_union_is_user_id(false), m_union_is_isa_ptr(false), + m_has_object_ptr(false), m_is_self(false), m_is_dynamic_cxx(true), + m_is_forcefully_completed(false) {} + + bool GetIsDynamicCXXType() const { return m_is_dynamic_cxx; } + + void SetIsDynamicCXXType(bool b) { m_is_dynamic_cxx = b; } + + void SetUserID(lldb::user_id_t user_id) { + m_user_id = user_id; + m_union_is_user_id = true; + m_union_is_isa_ptr = false; + } + + lldb::user_id_t GetUserID() const { + if (m_union_is_user_id) + return m_user_id; + else + return LLDB_INVALID_UID; + } + + void SetISAPtr(uint64_t isa_ptr) { + m_isa_ptr = isa_ptr; + m_union_is_user_id = false; + m_union_is_isa_ptr = true; + } + + uint64_t GetISAPtr() const { + if (m_union_is_isa_ptr) + return m_isa_ptr; + else + return 0; + } + + void SetObjectPtrName(const char *name) { + m_has_object_ptr = true; + if (strcmp(name, "self") == 0) + m_is_self = true; + else if (strcmp(name, "this") == 0) + m_is_self = false; + else + m_has_object_ptr = false; + } + + lldb::LanguageType GetObjectPtrLanguage() const { + if (m_has_object_ptr) { + if (m_is_self) + return lldb::eLanguageTypeObjC; + else + return lldb::eLanguageTypeC_plus_plus; + } + return lldb::eLanguageTypeUnknown; + } + + const char *GetObjectPtrName() const { + if (m_has_object_ptr) { + if (m_is_self) + return "self"; + else + return "this"; + } else + return nullptr; + } + + bool HasObjectPtr() const { return m_has_object_ptr; } + + /// A type is "forcefully completed" if it was declared complete to satisfy an + /// AST invariant (e.g. base classes must be complete types), but in fact we + /// were not able to find a actual definition for it. + bool IsForcefullyCompleted() const { return m_is_forcefully_completed; } + + void SetIsForcefullyCompleted(bool value = true) { + m_is_forcefully_completed = true; + } + + void Dump(Stream *s); + +private: + union { + lldb::user_id_t m_user_id; + uint64_t m_isa_ptr; + }; + + bool m_union_is_user_id : 1, m_union_is_isa_ptr : 1, m_has_object_ptr : 1, + m_is_self : 1, m_is_dynamic_cxx : 1, m_is_forcefully_completed : 1; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTMETADATA_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 42927ab6cc8a..6fe85a1298fc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -1,4 +1,4 @@ -//===-- ClangASTSource.cpp ---------------------------------------*- C++-*-===// +//===-- ClangASTSource.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,8 +13,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolFile.h" @@ -23,8 +21,11 @@ #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/Basic/SourceManager.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include <memory> #include <vector> @@ -49,14 +50,16 @@ private: }; } -ClangASTSource::ClangASTSource(const lldb::TargetSP &target, - const lldb::ClangASTImporterSP &importer) - : m_import_in_progress(false), m_lookups_enabled(false), m_target(target), - m_ast_context(nullptr), m_active_lexical_decls(), m_active_lookups() { - m_ast_importer_sp = importer; +ClangASTSource::ClangASTSource( + const lldb::TargetSP &target, + const std::shared_ptr<ClangASTImporter> &importer) + : m_lookups_enabled(false), m_target(target), m_ast_context(nullptr), + m_ast_importer_sp(importer), m_active_lexical_decls(), + m_active_lookups() { + assert(m_ast_importer_sp && "No ClangASTImporter passed to ClangASTSource?"); } -void ClangASTSource::InstallASTContext(ClangASTContext &clang_ast_context) { +void ClangASTSource::InstallASTContext(TypeSystemClang &clang_ast_context) { m_ast_context = &clang_ast_context.getASTContext(); m_clang_ast_context = &clang_ast_context; m_file_manager = &m_ast_context->getSourceManager().getFileManager(); @@ -64,18 +67,15 @@ void ClangASTSource::InstallASTContext(ClangASTContext &clang_ast_context) { } ClangASTSource::~ClangASTSource() { - if (!m_ast_importer_sp) - return; - m_ast_importer_sp->ForgetDestination(m_ast_context); if (!m_target) return; // We are in the process of destruction, don't create clang ast context on // demand by passing false to - // Target::GetScratchClangASTContext(create_on_demand). - ClangASTContext *scratch_clang_ast_context = - ClangASTContext::GetScratch(*m_target, false); + // Target::GetScratchTypeSystemClang(create_on_demand). + TypeSystemClang *scratch_clang_ast_context = + TypeSystemClang::GetScratch(*m_target, false); if (!scratch_clang_ast_context) return; @@ -103,16 +103,8 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( return false; } - if (GetImportInProgress()) { - SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); - return false; - } - std::string decl_name(clang_decl_name.getAsString()); - // if (m_decl_map.DoingASTImport ()) - // return DeclContext::lookup_result(); - // switch (clang_decl_name.getNameKind()) { // Normal identifiers. case DeclarationName::Identifier: { @@ -141,7 +133,7 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( case DeclarationName::ObjCMultiArgSelector: { llvm::SmallVector<NamedDecl *, 1> method_decls; - NameSearchContext method_search_context(*this, method_decls, + NameSearchContext method_search_context(*m_clang_ast_context, method_decls, clang_decl_name, decl_ctx); FindObjCMethodDecls(method_search_context); @@ -179,154 +171,134 @@ bool ClangASTSource::FindExternalVisibleDeclsByName( return false; } m_active_lookups.insert(uniqued_const_decl_name); - // static uint32_t g_depth = 0; - // ++g_depth; - // printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth, - // uniqued_const_decl_name); llvm::SmallVector<NamedDecl *, 4> name_decls; - NameSearchContext name_search_context(*this, name_decls, clang_decl_name, - decl_ctx); + NameSearchContext name_search_context(*m_clang_ast_context, name_decls, + clang_decl_name, decl_ctx); FindExternalVisibleDecls(name_search_context); SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, name_decls); - // --g_depth; m_active_lookups.erase(uniqued_const_decl_name); return (name_decls.size() != 0); } -void ClangASTSource::CompleteType(TagDecl *tag_decl) { +TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - if (log) { - LLDB_LOGF(log, - " CompleteTagDecl[%u] on (ASTContext*)%p Completing " - "(TagDecl*)%p named %s", - current_id, static_cast<void *>(m_ast_context), - static_cast<void *>(tag_decl), tag_decl->getName().str().c_str()); - - LLDB_LOG(log, " CTD[%u] Before:\n{0}", current_id, - ClangUtil::DumpDecl(tag_decl)); - } - - auto iter = m_active_lexical_decls.find(tag_decl); - if (iter != m_active_lexical_decls.end()) - return; - m_active_lexical_decls.insert(tag_decl); - ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); + if (const NamespaceDecl *namespace_context = + dyn_cast<NamespaceDecl>(decl->getDeclContext())) { + ClangASTImporter::NamespaceMapSP namespace_map = + m_ast_importer_sp->GetNamespaceMap(namespace_context); - if (!m_ast_importer_sp) { - return; - } + LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)", + namespace_map.get(), namespace_map->size()); - if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) { - // We couldn't complete the type. Maybe there's a definition somewhere - // else that can be completed. - - LLDB_LOGF(log, - " CTD[%u] Type could not be completed in the module in " - "which it was first found.", - current_id); + if (!namespace_map) + return nullptr; - bool found = false; + for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) { + LLDB_LOG(log, " CTD Searching namespace {0} in module {1}", + item.second.GetName(), item.first->GetFileSpec().GetFilename()); - DeclContext *decl_ctx = tag_decl->getDeclContext(); + TypeList types; - if (const NamespaceDecl *namespace_context = - dyn_cast<NamespaceDecl>(decl_ctx)) { - ClangASTImporter::NamespaceMapSP namespace_map = - m_ast_importer_sp->GetNamespaceMap(namespace_context); + ConstString name(decl->getName()); - if (log && log->GetVerbose()) - LLDB_LOGF(log, " CTD[%u] Inspecting namespace map %p (%d entries)", - current_id, static_cast<void *>(namespace_map.get()), - static_cast<int>(namespace_map->size())); + item.first->FindTypesInNamespace(name, item.second, UINT32_MAX, types); - if (!namespace_map) - return; + for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { + lldb::TypeSP type = types.GetTypeAtIndex(ti); - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), - e = namespace_map->end(); - i != e && !found; ++i) { - LLDB_LOGF(log, " CTD[%u] Searching namespace %s in module %s", - current_id, i->second.GetName().AsCString(), - i->first->GetFileSpec().GetFilename().GetCString()); + if (!type) + continue; - TypeList types; + CompilerType clang_type(type->GetFullCompilerType()); - ConstString name(tag_decl->getName().str().c_str()); + if (!ClangUtil::IsClangType(clang_type)) + continue; - i->first->FindTypesInNamespace(name, &i->second, UINT32_MAX, types); + const TagType *tag_type = + ClangUtil::GetQualType(clang_type)->getAs<TagType>(); - for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); + if (!tag_type) + continue; - if (!type) - continue; + TagDecl *candidate_tag_decl = + const_cast<TagDecl *>(tag_type->getDecl()); - CompilerType clang_type(type->GetFullCompilerType()); + if (TypeSystemClang::GetCompleteDecl( + &candidate_tag_decl->getASTContext(), candidate_tag_decl)) + return candidate_tag_decl; + } + } + } else { + TypeList types; - if (!ClangUtil::IsClangType(clang_type)) - continue; + ConstString name(decl->getName()); - const TagType *tag_type = - ClangUtil::GetQualType(clang_type)->getAs<TagType>(); + const ModuleList &module_list = m_target->GetImages(); - if (!tag_type) - continue; + bool exact_match = false; + llvm::DenseSet<SymbolFile *> searched_symbol_files; + module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, + searched_symbol_files, types); - TagDecl *candidate_tag_decl = - const_cast<TagDecl *>(tag_type->getDecl()); + for (uint32_t ti = 0, te = types.GetSize(); ti != te; ++ti) { + lldb::TypeSP type = types.GetTypeAtIndex(ti); - if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, - candidate_tag_decl)) - found = true; - } - } - } else { - TypeList types; + if (!type) + continue; - ConstString name(tag_decl->getName().str().c_str()); + CompilerType clang_type(type->GetFullCompilerType()); - const ModuleList &module_list = m_target->GetImages(); + if (!ClangUtil::IsClangType(clang_type)) + continue; - bool exact_match = false; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - module_list.FindTypes(nullptr, name, exact_match, UINT32_MAX, - searched_symbol_files, types); + const TagType *tag_type = + ClangUtil::GetQualType(clang_type)->getAs<TagType>(); - for (uint32_t ti = 0, te = types.GetSize(); ti != te && !found; ++ti) { - lldb::TypeSP type = types.GetTypeAtIndex(ti); + if (!tag_type) + continue; - if (!type) - continue; + TagDecl *candidate_tag_decl = const_cast<TagDecl *>(tag_type->getDecl()); - CompilerType clang_type(type->GetFullCompilerType()); + // We have found a type by basename and we need to make sure the decl + // contexts are the same before we can try to complete this type with + // another + if (!TypeSystemClang::DeclsAreEquivalent(const_cast<TagDecl *>(decl), + candidate_tag_decl)) + continue; - if (!ClangUtil::IsClangType(clang_type)) - continue; + if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(), + candidate_tag_decl)) + return candidate_tag_decl; + } + } + return nullptr; +} - const TagType *tag_type = - ClangUtil::GetQualType(clang_type)->getAs<TagType>(); +void ClangASTSource::CompleteType(TagDecl *tag_decl) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (!tag_type) - continue; + if (log) { + LLDB_LOG(log, + " CompleteTagDecl on (ASTContext*){0} Completing " + "(TagDecl*){1} named {2}", + m_clang_ast_context->getDisplayName(), tag_decl, + tag_decl->getName()); - TagDecl *candidate_tag_decl = - const_cast<TagDecl *>(tag_type->getDecl()); + LLDB_LOG(log, " CTD Before:\n{0}", ClangUtil::DumpDecl(tag_decl)); + } - // We have found a type by basename and we need to make sure the decl - // contexts are the same before we can try to complete this type with - // another - if (!ClangASTContext::DeclsAreEquivalent(tag_decl, candidate_tag_decl)) - continue; + auto iter = m_active_lexical_decls.find(tag_decl); + if (iter != m_active_lexical_decls.end()) + return; + m_active_lexical_decls.insert(tag_decl); + ScopedLexicalDeclEraser eraser(m_active_lexical_decls, tag_decl); - if (m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, - candidate_tag_decl)) - found = true; - } - } + if (!m_ast_importer_sp->CompleteTagDecl(tag_decl)) { + // We couldn't complete the type. Maybe there's a definition somewhere + // else that can be completed. + if (TagDecl *alternate = FindCompleteType(tag_decl)) + m_ast_importer_sp->CompleteTagDeclWithOrigin(tag_decl, alternate); } LLDB_LOG(log, " [CTD] After:\n{0}", ClangUtil::DumpDecl(tag_decl)); @@ -335,19 +307,14 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOGF(log, - " [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing " - "an ObjCInterfaceDecl named %s", - static_cast<void *>(m_ast_context), - interface_decl->getName().str().c_str()); + LLDB_LOG(log, + " [CompleteObjCInterfaceDecl] on (ASTContext*){0} '{1}' " + "Completing an ObjCInterfaceDecl named {1}", + m_ast_context, m_clang_ast_context->getDisplayName(), + interface_decl->getName()); LLDB_LOG(log, " [COID] Before:\n{0}", ClangUtil::DumpDecl(interface_decl)); - if (!m_ast_importer_sp) { - lldbassert(0 && "No mechanism for completing a type!"); - return; - } - ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(interface_decl); if (original.Valid()) { @@ -368,10 +335,8 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { interface_decl->getSuperClass() != interface_decl) CompleteType(interface_decl->getSuperClass()); - if (log) { - LLDB_LOGF(log, " [COID] After:"); - LLDB_LOG(log, " [COID] {0}", ClangUtil::DumpDecl(interface_decl)); - } + LLDB_LOG(log, " [COID] After:"); + LLDB_LOG(log, " [COID] {0}", ClangUtil::DumpDecl(interface_decl)); } clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface( @@ -420,9 +385,6 @@ void ClangASTSource::FindExternalLexicalDecls( llvm::function_ref<bool(Decl::Kind)> predicate, llvm::SmallVectorImpl<Decl *> &decls) { - if (!m_ast_importer_sp) - return; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); const Decl *context_decl = dyn_cast<Decl>(decl_context); @@ -436,29 +398,27 @@ void ClangASTSource::FindExternalLexicalDecls( m_active_lexical_decls.insert(context_decl); ScopedLexicalDeclEraser eraser(m_active_lexical_decls, context_decl); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - if (log) { if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) - LLDB_LOGF( - log, - "FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p", - current_id, static_cast<void *>(m_ast_context), - context_named_decl->getNameAsString().c_str(), - context_decl->getDeclKindName(), - static_cast<const void *>(context_decl)); + LLDB_LOG(log, + "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in " + "'{2}' (%sDecl*){3}", + m_ast_context, m_clang_ast_context->getDisplayName(), + context_named_decl->getNameAsString().c_str(), + context_decl->getDeclKindName(), + static_cast<const void *>(context_decl)); else if (context_decl) - LLDB_LOGF( - log, "FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p", - current_id, static_cast<void *>(m_ast_context), - context_decl->getDeclKindName(), - static_cast<const void *>(context_decl)); + LLDB_LOG(log, + "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in " + "({2}Decl*){3}", + m_ast_context, m_clang_ast_context->getDisplayName(), + context_decl->getDeclKindName(), + static_cast<const void *>(context_decl)); else - LLDB_LOGF( - log, - "FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context", - current_id, static_cast<const void *>(m_ast_context)); + LLDB_LOG(log, + "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in a " + "NULL context", + m_ast_context, m_clang_ast_context->getDisplayName()); } ClangASTImporter::DeclOrigin original = m_ast_importer_sp->GetDeclOrigin(context_decl); @@ -466,10 +426,10 @@ void ClangASTSource::FindExternalLexicalDecls( if (!original.Valid()) return; - LLDB_LOG( - log, " FELD[{0}] Original decl (ASTContext*){1:x} (Decl*){2:x}:\n{3}", - current_id, static_cast<void *>(original.ctx), - static_cast<void *>(original.decl), ClangUtil::DumpDecl(original.decl)); + LLDB_LOG(log, " FELD Original decl {0} (Decl*){1:x}:\n{2}", + static_cast<void *>(original.ctx), + static_cast<void *>(original.decl), + ClangUtil::DumpDecl(original.decl)); if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original.decl)) { @@ -499,10 +459,7 @@ void ClangASTSource::FindExternalLexicalDecls( // Indicates whether we skipped any Decls of the original DeclContext. bool SkippedDecls = false; - for (TagDecl::decl_iterator iter = original_decl_context->decls_begin(); - iter != original_decl_context->decls_end(); ++iter) { - Decl *decl = *iter; - + for (Decl *decl : original_decl_context->decls()) { // The predicate function returns true if the passed declaration kind is // the one we are looking for. // See clang::ExternalASTSource::FindExternalLexicalDecls() @@ -511,13 +468,13 @@ void ClangASTSource::FindExternalLexicalDecls( std::string ast_dump = ClangUtil::DumpDecl(decl); if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) - LLDB_LOGF(log, " FELD[%d] Adding [to %sDecl %s] lexical %sDecl %s", - current_id, context_named_decl->getDeclKindName(), - context_named_decl->getNameAsString().c_str(), - decl->getDeclKindName(), ast_dump.c_str()); + LLDB_LOG(log, " FELD Adding [to {0}Decl {1}] lexical {2}Decl {3}", + context_named_decl->getDeclKindName(), + context_named_decl->getName(), decl->getDeclKindName(), + ast_dump); else - LLDB_LOGF(log, " FELD[%d] Adding lexical %sDecl %s", current_id, - decl->getDeclKindName(), ast_dump.c_str()); + LLDB_LOG(log, " FELD Adding lexical {0}Decl {1}", + decl->getDeclKindName(), ast_dump); } Decl *copied_decl = CopyDecl(decl); @@ -556,56 +513,29 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - if (log) { if (!context.m_decl_context) - LLDB_LOGF(log, - "ClangASTSource::FindExternalVisibleDecls[%u] on " - "(ASTContext*)%p for '%s' in a NULL DeclContext", - current_id, static_cast<void *>(m_ast_context), - name.GetCString()); + LLDB_LOG(log, + "ClangASTSource::FindExternalVisibleDecls on " + "(ASTContext*){0} '{1}' for '{2}' in a NULL DeclContext", + m_ast_context, m_clang_ast_context->getDisplayName(), name); else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context)) - LLDB_LOGF(log, - "ClangASTSource::FindExternalVisibleDecls[%u] on " - "(ASTContext*)%p for '%s' in '%s'", - current_id, static_cast<void *>(m_ast_context), - name.GetCString(), - context_named_decl->getNameAsString().c_str()); + LLDB_LOG(log, + "ClangASTSource::FindExternalVisibleDecls on " + "(ASTContext*){0} '{1}' for '{2}' in '{3}'", + m_ast_context, m_clang_ast_context->getDisplayName(), name, + context_named_decl->getName()); else - LLDB_LOGF(log, - "ClangASTSource::FindExternalVisibleDecls[%u] on " - "(ASTContext*)%p for '%s' in a '%s'", - current_id, static_cast<void *>(m_ast_context), - name.GetCString(), context.m_decl_context->getDeclKindName()); + LLDB_LOG(log, + "ClangASTSource::FindExternalVisibleDecls on " + "(ASTContext*){0} '{1}' for '{2}' in a '{3}'", + m_ast_context, m_clang_ast_context->getDisplayName(), name, + context.m_decl_context->getDeclKindName()); } - context.m_namespace_map = std::make_shared<ClangASTImporter::NamespaceMap>(); - - if (const NamespaceDecl *namespace_context = - dyn_cast<NamespaceDecl>(context.m_decl_context)) { - ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp ? - m_ast_importer_sp->GetNamespaceMap(namespace_context) : nullptr; - - if (log && log->GetVerbose()) - LLDB_LOGF(log, " CAS::FEVD[%u] Inspecting namespace map %p (%d entries)", - current_id, static_cast<void *>(namespace_map.get()), - static_cast<int>(namespace_map->size())); - - if (!namespace_map) - return; - - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), - e = namespace_map->end(); - i != e; ++i) { - LLDB_LOGF(log, " CAS::FEVD[%u] Searching namespace %s in module %s", - current_id, i->second.GetName().AsCString(), - i->first->GetFileSpec().GetFilename().GetCString()); - - FindExternalVisibleDecls(context, i->first, i->second, current_id); - } + if (isa<NamespaceDecl>(context.m_decl_context)) { + LookupInNamespace(context); } else if (isa<ObjCInterfaceDecl>(context.m_decl_context)) { FindObjCPropertyAndIvarDecls(context); } else if (!isa<TranslationUnitDecl>(context.m_decl_context)) { @@ -614,18 +544,15 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { } else { CompilerDeclContext namespace_decl; - LLDB_LOGF(log, " CAS::FEVD[%u] Searching the root namespace", current_id); + LLDB_LOG(log, " CAS::FEVD Searching the root namespace"); - FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl, - current_id); + FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl); } if (!context.m_namespace_map->empty()) { if (log && log->GetVerbose()) - LLDB_LOGF(log, - " CAS::FEVD[%u] Registering namespace map %p (%d entries)", - current_id, static_cast<void *>(context.m_namespace_map.get()), - static_cast<int>(context.m_namespace_map->size())); + LLDB_LOG(log, " CAS::FEVD Registering namespace map {0} ({1} entries)", + context.m_namespace_map.get(), context.m_namespace_map->size()); NamespaceDecl *clang_namespace_decl = AddNamespace(context, context.m_namespace_map); @@ -658,7 +585,7 @@ bool ClangASTSource::IgnoreName(const ConstString name, void ClangASTSource::FindExternalVisibleDecls( NameSearchContext &context, lldb::ModuleSP module_sp, - CompilerDeclContext &namespace_decl, unsigned int current_id) { + CompilerDeclContext &namespace_decl) { assert(m_ast_context); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -672,196 +599,113 @@ void ClangASTSource::FindExternalVisibleDecls( if (!m_target) return; - if (module_sp && namespace_decl) { - CompilerDeclContext found_namespace_decl; - - if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) { - found_namespace_decl = symbol_file->FindNamespace(name, &namespace_decl); + FillNamespaceMap(context, module_sp, namespace_decl); - if (found_namespace_decl) { - context.m_namespace_map->push_back( - std::pair<lldb::ModuleSP, CompilerDeclContext>( - module_sp, found_namespace_decl)); - - LLDB_LOGF(log, " CAS::FEVD[%u] Found namespace %s in module %s", - current_id, name.GetCString(), - module_sp->GetFileSpec().GetFilename().GetCString()); - } - } - } else { - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); + if (context.m_found_type) + return; - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); + TypeList types; + const bool exact_match = true; + llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; + if (module_sp && namespace_decl) + module_sp->FindTypesInNamespace(name, namespace_decl, 1, types); + else { + m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, + searched_symbol_files, types); + } - if (!image) - continue; + if (size_t num_types = types.GetSize()) { + for (size_t ti = 0; ti < num_types; ++ti) { + lldb::TypeSP type_sp = types.GetTypeAtIndex(ti); - CompilerDeclContext found_namespace_decl; + if (log) { + const char *name_string = type_sp->GetName().GetCString(); - SymbolFile *symbol_file = image->GetSymbolFile(); + LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\": {1}", name, + (name_string ? name_string : "<anonymous>")); + } - if (!symbol_file) - continue; + CompilerType full_type = type_sp->GetFullCompilerType(); - found_namespace_decl = symbol_file->FindNamespace(name, &namespace_decl); + CompilerType copied_clang_type(GuardedCopyType(full_type)); - if (found_namespace_decl) { - context.m_namespace_map->push_back( - std::pair<lldb::ModuleSP, CompilerDeclContext>( - image, found_namespace_decl)); + if (!copied_clang_type) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type"); - LLDB_LOGF(log, " CAS::FEVD[%u] Found namespace %s in module %s", - current_id, name.GetCString(), - image->GetFileSpec().GetFilename().GetCString()); + continue; } - } - } - do { - if (context.m_found.type) - break; + context.AddTypeDecl(copied_clang_type); - TypeList types; - const bool exact_match = true; - llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; - if (module_sp && namespace_decl) - module_sp->FindTypesInNamespace(name, &namespace_decl, 1, types); - else { - m_target->GetImages().FindTypes(module_sp.get(), name, exact_match, 1, - searched_symbol_files, types); + context.m_found_type = true; + break; } + } - if (size_t num_types = types.GetSize()) { - for (size_t ti = 0; ti < num_types; ++ti) { - lldb::TypeSP type_sp = types.GetTypeAtIndex(ti); - - if (log) { - const char *name_string = type_sp->GetName().GetCString(); + if (!context.m_found_type) { + // Try the modules next. + FindDeclInModules(context, name); + } - LLDB_LOGF(log, " CAS::FEVD[%u] Matching type found for \"%s\": %s", - current_id, name.GetCString(), - (name_string ? name_string : "<anonymous>")); - } + if (!context.m_found_type) { + FindDeclInObjCRuntime(context, name); + } +} - CompilerType full_type = type_sp->GetFullCompilerType(); +void ClangASTSource::FillNamespaceMap( + NameSearchContext &context, lldb::ModuleSP module_sp, + const CompilerDeclContext &namespace_decl) { + const ConstString name(context.m_decl_name.getAsString().c_str()); + if (IgnoreName(name, true)) + return; - CompilerType copied_clang_type(GuardedCopyType(full_type)); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (!copied_clang_type) { - LLDB_LOGF(log, " CAS::FEVD[%u] - Couldn't export a type", - current_id); + if (module_sp && namespace_decl) { + CompilerDeclContext found_namespace_decl; - continue; - } + if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) { + found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl); - context.AddTypeDecl(copied_clang_type); + if (found_namespace_decl) { + context.m_namespace_map->push_back( + std::pair<lldb::ModuleSP, CompilerDeclContext>( + module_sp, found_namespace_decl)); - context.m_found.type = true; - break; + LLDB_LOG(log, " CAS::FEVD Found namespace {0} in module {1}", name, + module_sp->GetFileSpec().GetFilename()); } } + return; + } - if (!context.m_found.type) { - // Try the modules next. - - do { - if (ClangModulesDeclVendor *modules_decl_vendor = - m_target->GetClangModulesDeclVendor()) { - bool append = false; - uint32_t max_matches = 1; - std::vector<clang::NamedDecl *> decls; - - if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) - break; - - if (log) { - LLDB_LOGF(log, - " CAS::FEVD[%u] Matching entity found for \"%s\" in " - "the modules", - current_id, name.GetCString()); - } - - clang::NamedDecl *const decl_from_modules = decls[0]; - - if (llvm::isa<clang::TypeDecl>(decl_from_modules) || - llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) || - llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) { - clang::Decl *copied_decl = CopyDecl(decl_from_modules); - clang::NamedDecl *copied_named_decl = - copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; - - if (!copied_named_decl) { - LLDB_LOGF( - log, - " CAS::FEVD[%u] - Couldn't export a type from the modules", - current_id); - - break; - } - - context.AddNamedDecl(copied_named_decl); - - context.m_found.type = true; - } - } - } while (false); - } - - if (!context.m_found.type) { - do { - // Couldn't find any types elsewhere. Try the Objective-C runtime if - // one exists. - - lldb::ProcessSP process(m_target->GetProcessSP()); - - if (!process) - break; - - ObjCLanguageRuntime *language_runtime( - ObjCLanguageRuntime::Get(*process)); - - if (!language_runtime) - break; - - DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + const ModuleList &target_images = m_target->GetImages(); + std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - if (!decl_vendor) - break; + for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { + lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - bool append = false; - uint32_t max_matches = 1; - std::vector<clang::NamedDecl *> decls; + if (!image) + continue; - auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); - if (!clang_decl_vendor->FindDecls(name, append, max_matches, decls)) - break; + CompilerDeclContext found_namespace_decl; - if (log) { - LLDB_LOGF( - log, - " CAS::FEVD[%u] Matching type found for \"%s\" in the runtime", - current_id, name.GetCString()); - } + SymbolFile *symbol_file = image->GetSymbolFile(); - clang::Decl *copied_decl = CopyDecl(decls[0]); - clang::NamedDecl *copied_named_decl = - copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + if (!symbol_file) + continue; - if (!copied_named_decl) { - LLDB_LOGF(log, - " CAS::FEVD[%u] - Couldn't export a type from the runtime", - current_id); + found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl); - break; - } + if (found_namespace_decl) { + context.m_namespace_map->push_back( + std::pair<lldb::ModuleSP, CompilerDeclContext>(image, + found_namespace_decl)); - context.AddNamedDecl(copied_named_decl); - } while (false); + LLDB_LOG(log, " CAS::FEVD Found namespace {0} in module {1}", name, + image->GetFileSpec().GetFilename()); } - - } while (false); + } } template <class D> class TaggedASTDecl { @@ -915,8 +759,8 @@ DeclFromParser<D> DeclFromUser<D>::Import(ClangASTSource &source) { } bool ClangASTSource::FindObjCMethodDeclsWithOrigin( - unsigned int current_id, NameSearchContext &context, - ObjCInterfaceDecl *original_interface_decl, const char *log_info) { + NameSearchContext &context, ObjCInterfaceDecl *original_interface_decl, + const char *log_info) { const DeclarationName &decl_name(context.m_decl_name); clang::ASTContext *original_ctx = &original_interface_decl->getASTContext(); @@ -951,7 +795,7 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( llvm::SmallVector<NamedDecl *, 1> methods; - ClangASTContext::GetCompleteDecl(original_ctx, original_interface_decl); + TypeSystemClang::GetCompleteDecl(original_ctx, original_interface_decl); if (ObjCMethodDecl *instance_method_decl = original_interface_decl->lookupInstanceMethod(original_selector)) { @@ -987,7 +831,7 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOG(log, " CAS::FOMD[{0}] found ({1}) {2}", current_id, log_info, + LLDB_LOG(log, " CAS::FOMD found ({0}) {1}", log_info, ClangUtil::DumpDecl(copied_method_decl)); context.AddNamedDecl(copied_method_decl); @@ -996,11 +840,91 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( return true; } -void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { +void ClangASTSource::FindDeclInModules(NameSearchContext &context, + ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; + ClangModulesDeclVendor *modules_decl_vendor = + m_target->GetClangModulesDeclVendor(); + if (!modules_decl_vendor) + return; + + bool append = false; + uint32_t max_matches = 1; + std::vector<clang::NamedDecl *> decls; + + if (!modules_decl_vendor->FindDecls(name, append, max_matches, decls)) + return; + + LLDB_LOG(log, " CAS::FEVD Matching entity found for \"{0}\" in the modules", + name); + + clang::NamedDecl *const decl_from_modules = decls[0]; + + if (llvm::isa<clang::TypeDecl>(decl_from_modules) || + llvm::isa<clang::ObjCContainerDecl>(decl_from_modules) || + llvm::isa<clang::EnumConstantDecl>(decl_from_modules)) { + clang::Decl *copied_decl = CopyDecl(decl_from_modules); + clang::NamedDecl *copied_named_decl = + copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + + if (!copied_named_decl) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type from the modules"); + + return; + } + + context.AddNamedDecl(copied_named_decl); + + context.m_found_type = true; + } +} + +void ClangASTSource::FindDeclInObjCRuntime(NameSearchContext &context, + ConstString name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + lldb::ProcessSP process(m_target->GetProcessSP()); + + if (!process) + return; + + ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process)); + + if (!language_runtime) + return; + + DeclVendor *decl_vendor = language_runtime->GetDeclVendor(); + + if (!decl_vendor) + return; + + bool append = false; + uint32_t max_matches = 1; + std::vector<clang::NamedDecl *> decls; + + auto *clang_decl_vendor = llvm::cast<ClangDeclVendor>(decl_vendor); + if (!clang_decl_vendor->FindDecls(name, append, max_matches, decls)) + return; + + LLDB_LOG(log, " CAS::FEVD Matching type found for \"{0}\" in the runtime", + name); + + clang::Decl *copied_decl = CopyDecl(decls[0]); + clang::NamedDecl *copied_named_decl = + copied_decl ? dyn_cast<clang::NamedDecl>(copied_decl) : nullptr; + + if (!copied_named_decl) { + LLDB_LOG(log, " CAS::FEVD - Couldn't export a type from the runtime"); + + return; + } + + context.AddNamedDecl(copied_named_decl); +} + +void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); const DeclarationName &decl_name(context.m_decl_name); const DeclContext *decl_ctx(context.m_decl_context); @@ -1020,8 +944,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { ObjCInterfaceDecl *original_interface_decl = dyn_cast<ObjCInterfaceDecl>(original.decl); - if (FindObjCMethodDeclsWithOrigin(current_id, context, - original_interface_decl, "at origin")) + if (FindObjCMethodDeclsWithOrigin(context, original_interface_decl, + "at origin")) return; // found it, no need to look any further } while (false); @@ -1046,12 +970,11 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { ConstString selector_name(ss.GetString()); - LLDB_LOGF(log, - "ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p " - "for selector [%s %s]", - current_id, static_cast<void *>(m_ast_context), - interface_decl->getNameAsString().c_str(), - selector_name.AsCString()); + LLDB_LOG(log, + "ClangASTSource::FindObjCMethodDecls on (ASTContext*){0} '{1}' " + "for selector [{2} {3}]", + m_ast_context, m_clang_ast_context->getDisplayName(), + interface_decl->getName(), selector_name); SymbolContextList sc_list; const bool include_symbols = false; @@ -1148,7 +1071,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { continue; ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); + TypeSystemClang::DeclContextGetAsObjCMethodDecl(function_decl_ctx); if (!method_decl) continue; @@ -1171,7 +1094,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!copied_method_decl) continue; - LLDB_LOG(log, " CAS::FOMD[{0}] found (in symbols)\n{1}", current_id, + LLDB_LOG(log, " CAS::FOMD found (in symbols)\n{0}", ClangUtil::DumpDecl(copied_method_decl)); context.AddNamedDecl(copied_method_decl); @@ -1199,13 +1122,12 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (complete_interface_decl == interface_decl) break; // already checked this one - LLDB_LOGF(log, - "CAS::FOPD[%d] trying origin " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<void *>(complete_interface_decl), - static_cast<void *>(&complete_iface_decl->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD trying origin " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + complete_interface_decl, &complete_iface_decl->getASTContext()); - FindObjCMethodDeclsWithOrigin(current_id, context, complete_interface_decl, + FindObjCMethodDeclsWithOrigin(context, complete_interface_decl, "in debug info"); return; @@ -1232,8 +1154,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!interface_decl_from_modules) break; - if (FindObjCMethodDeclsWithOrigin( - current_id, context, interface_decl_from_modules, "in modules")) + if (FindObjCMethodDeclsWithOrigin(context, interface_decl_from_modules, + "in modules")) return; } } while (false); @@ -1273,13 +1195,13 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { if (!runtime_interface_decl) break; - FindObjCMethodDeclsWithOrigin(current_id, context, runtime_interface_decl, + FindObjCMethodDeclsWithOrigin(context, runtime_interface_decl, "in runtime"); } while (false); } static bool FindObjCPropertyAndIvarDeclsWithOrigin( - unsigned int current_id, NameSearchContext &context, ClangASTSource &source, + NameSearchContext &context, ClangASTSource &source, DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1301,7 +1223,7 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( DeclFromParser<ObjCPropertyDecl> parser_property_decl( origin_property_decl.Import(source)); if (parser_property_decl.IsValid()) { - LLDB_LOG(log, " CAS::FOPD[{0}] found\n{1}", current_id, + LLDB_LOG(log, " CAS::FOPD found\n{0}", ClangUtil::DumpDecl(parser_property_decl.decl)); context.AddNamedDecl(parser_property_decl.decl); @@ -1316,10 +1238,8 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( DeclFromParser<ObjCIvarDecl> parser_ivar_decl( origin_ivar_decl.Import(source)); if (parser_ivar_decl.IsValid()) { - if (log) { - LLDB_LOG(log, " CAS::FOPD[{0}] found\n{1}", current_id, - ClangUtil::DumpDecl(parser_ivar_decl.decl)); - } + LLDB_LOG(log, " CAS::FOPD found\n{0}", + ClangUtil::DumpDecl(parser_ivar_decl.decl)); context.AddNamedDecl(parser_ivar_decl.decl); found = true; @@ -1332,9 +1252,6 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl( cast<ObjCInterfaceDecl>(context.m_decl_context)); DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl( @@ -1342,23 +1259,20 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { ConstString class_name(parser_iface_decl->getNameAsString().c_str()); - LLDB_LOGF(log, - "ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on " - "(ASTContext*)%p for '%s.%s'", - current_id, static_cast<void *>(m_ast_context), - parser_iface_decl->getNameAsString().c_str(), - context.m_decl_name.getAsString().c_str()); + LLDB_LOG(log, + "ClangASTSource::FindObjCPropertyAndIvarDecls on " + "(ASTContext*){0} '{1}' for '{2}.{3}'", + m_ast_context, m_clang_ast_context->getDisplayName(), + parser_iface_decl->getName(), context.m_decl_name.getAsString()); - if (FindObjCPropertyAndIvarDeclsWithOrigin( - current_id, context, *this, origin_iface_decl)) + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, origin_iface_decl)) return; - LLDB_LOGF(log, - "CAS::FOPD[%d] couldn't find the property on origin " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching " - "elsewhere...", - current_id, static_cast<const void *>(origin_iface_decl.decl), - static_cast<void *>(&origin_iface_decl->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD couldn't find the property on origin " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}, searching " + "elsewhere...", + origin_iface_decl.decl, &origin_iface_decl->getASTContext()); SymbolContext null_sc; TypeList type_list; @@ -1379,14 +1293,12 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (complete_iface_decl.decl == origin_iface_decl.decl) break; // already checked this one - LLDB_LOGF(log, - "CAS::FOPD[%d] trying origin " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<const void *>(complete_iface_decl.decl), - static_cast<void *>(&complete_iface_decl->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD trying origin " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + complete_iface_decl.decl, &complete_iface_decl->getASTContext()); - FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, - complete_iface_decl); + FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, complete_iface_decl); return; } while (false); @@ -1414,14 +1326,13 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (!interface_decl_from_modules.IsValid()) break; - LLDB_LOGF( - log, - "CAS::FOPD[%d] trying module " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<const void *>(interface_decl_from_modules.decl), - static_cast<void *>(&interface_decl_from_modules->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD[{0}] trying module " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + interface_decl_from_modules.decl, + &interface_decl_from_modules->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this, + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, interface_decl_from_modules)) return; } while (false); @@ -1459,19 +1370,43 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { if (!interface_decl_from_runtime.IsValid()) break; - LLDB_LOGF( - log, - "CAS::FOPD[%d] trying runtime " - "(ObjCInterfaceDecl*)%p/(ASTContext*)%p...", - current_id, static_cast<const void *>(interface_decl_from_runtime.decl), - static_cast<void *>(&interface_decl_from_runtime->getASTContext())); + LLDB_LOG(log, + "CAS::FOPD[{0}] trying runtime " + "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + interface_decl_from_runtime.decl, + &interface_decl_from_runtime->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin( - current_id, context, *this, interface_decl_from_runtime)) + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, + interface_decl_from_runtime)) return; } while (false); } +void ClangASTSource::LookupInNamespace(NameSearchContext &context) { + const NamespaceDecl *namespace_context = + dyn_cast<NamespaceDecl>(context.m_decl_context); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + ClangASTImporter::NamespaceMapSP namespace_map = + m_ast_importer_sp->GetNamespaceMap(namespace_context); + + LLDB_LOGV(log, " CAS::FEVD Inspecting namespace map {0} ({1} entries)", + namespace_map.get(), namespace_map->size()); + + if (!namespace_map) + return; + + for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), + e = namespace_map->end(); + i != e; ++i) { + LLDB_LOG(log, " CAS::FEVD Searching namespace {0} in module {1}", + i->second.GetName(), i->first->GetFileSpec().GetFilename()); + + FindExternalVisibleDecls(context, i->first, i->second); + } +} + typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap; @@ -1557,17 +1492,14 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, FieldOffsetMap &field_offsets, BaseOffsetMap &base_offsets, BaseOffsetMap &virtual_base_offsets) { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - LLDB_LOGF(log, - "LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p " - "[name = '%s']", - current_id, static_cast<void *>(m_ast_context), - static_cast<const void *>(record), - record->getNameAsString().c_str()); + LLDB_LOG(log, + "LayoutRecordType on (ASTContext*){0} '{1}' for (RecordDecl*)" + "{3} [name = '{4}']", + m_ast_context, m_clang_ast_context->getDisplayName(), record, + record->getName()); DeclFromParser<const RecordDecl> parser_record(record); DeclFromUser<const RecordDecl> origin_record( @@ -1580,7 +1512,7 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, BaseOffsetMap origin_base_offsets; BaseOffsetMap origin_virtual_base_offsets; - ClangASTContext::GetCompleteDecl( + TypeSystemClang::GetCompleteDecl( &origin_record->getASTContext(), const_cast<RecordDecl *>(origin_record.decl)); @@ -1631,25 +1563,23 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, m_ast_context->getCharWidth(); if (log) { - LLDB_LOGF(log, "LRT[%u] returned:", current_id); - LLDB_LOGF(log, "LRT[%u] Original = (RecordDecl*)%p", current_id, - static_cast<const void *>(origin_record.decl)); - LLDB_LOGF(log, "LRT[%u] Size = %" PRId64, current_id, size); - LLDB_LOGF(log, "LRT[%u] Alignment = %" PRId64, current_id, alignment); - LLDB_LOGF(log, "LRT[%u] Fields:", current_id); + LLDB_LOG(log, "LRT returned:"); + LLDB_LOG(log, "LRT Original = (RecordDecl*)%p", + static_cast<const void *>(origin_record.decl)); + LLDB_LOG(log, "LRT Size = %" PRId64, size); + LLDB_LOG(log, "LRT Alignment = %" PRId64, alignment); + LLDB_LOG(log, "LRT Fields:"); for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end(); fi != fe; ++fi) { - LLDB_LOGF(log, - "LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 - " bits", - current_id, static_cast<void *>(*fi), - fi->getNameAsString().c_str(), field_offsets[*fi]); + LLDB_LOG(log, + "LRT (FieldDecl*){0}, Name = '{1}', Offset = {2} bits", + *fi, fi->getName(), field_offsets[*fi]); } DeclFromParser<const CXXRecordDecl> parser_cxx_record = DynCast<const CXXRecordDecl>(parser_record); if (parser_cxx_record.IsValid()) { - LLDB_LOGF(log, "LRT[%u] Bases:", current_id); + LLDB_LOG(log, "LRT Bases:"); for (CXXRecordDecl::base_class_const_iterator bi = parser_cxx_record->bases_begin(), be = parser_cxx_record->bases_end(); @@ -1662,19 +1592,17 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, DeclFromParser<CXXRecordDecl> base_cxx_record = DynCast<CXXRecordDecl>(base_record); - LLDB_LOGF( - log, - "LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 - " chars", - current_id, (is_virtual ? "Virtual " : ""), - static_cast<void *>(base_cxx_record.decl), - base_cxx_record.decl->getNameAsString().c_str(), - (is_virtual - ? virtual_base_offsets[base_cxx_record.decl].getQuantity() - : base_offsets[base_cxx_record.decl].getQuantity())); + LLDB_LOG(log, + "LRT {0}(CXXRecordDecl*){1}, Name = '{2}', Offset = " + "{3} chars", + (is_virtual ? "Virtual " : ""), base_cxx_record.decl, + base_cxx_record.decl->getName(), + (is_virtual + ? virtual_base_offsets[base_cxx_record.decl].getQuantity() + : base_offsets[base_cxx_record.decl].getQuantity())); } } else { - LLDB_LOGF(log, "LRD[%u] Not a CXXRecord, so no bases", current_id); + LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); } } @@ -1684,25 +1612,21 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, void ClangASTSource::CompleteNamespaceMap( ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name, ClangASTImporter::NamespaceMapSP &parent_map) const { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (log) { if (parent_map && parent_map->size()) - LLDB_LOGF(log, - "CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for " - "namespace %s in namespace %s", - current_id, static_cast<void *>(m_ast_context), - name.GetCString(), - parent_map->begin()->second.GetName().AsCString()); + LLDB_LOG(log, + "CompleteNamespaceMap on (ASTContext*){0} '{1}' Searching " + "for namespace {2} in namespace {3}", + m_ast_context, m_clang_ast_context->getDisplayName(), name, + parent_map->begin()->second.GetName()); else - LLDB_LOGF(log, - "CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for " - "namespace %s", - current_id, static_cast<void *>(m_ast_context), - name.GetCString()); + LLDB_LOG(log, + "CompleteNamespaceMap on (ASTContext*){0} '{1}' Searching " + "for namespace {2}", + m_ast_context, m_clang_ast_context->getDisplayName(), name); } if (parent_map) { @@ -1720,7 +1644,7 @@ void ClangASTSource::CompleteNamespaceMap( continue; found_namespace_decl = - symbol_file->FindNamespace(name, &module_parent_namespace_decl); + symbol_file->FindNamespace(name, module_parent_namespace_decl); if (!found_namespace_decl) continue; @@ -1728,9 +1652,8 @@ void ClangASTSource::CompleteNamespaceMap( namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>( module_sp, found_namespace_decl)); - LLDB_LOGF(log, " CMN[%u] Found namespace %s in module %s", current_id, - name.GetCString(), - module_sp->GetFileSpec().GetFilename().GetCString()); + LLDB_LOG(log, " CMN Found namespace {0} in module {1}", name, + module_sp->GetFileSpec().GetFilename()); } } else { const ModuleList &target_images = m_target->GetImages(); @@ -1752,7 +1675,7 @@ void ClangASTSource::CompleteNamespaceMap( continue; found_namespace_decl = - symbol_file->FindNamespace(name, &null_namespace_decl); + symbol_file->FindNamespace(name, null_namespace_decl); if (!found_namespace_decl) continue; @@ -1760,9 +1683,8 @@ void ClangASTSource::CompleteNamespaceMap( namespace_map->push_back(std::pair<lldb::ModuleSP, CompilerDeclContext>( image, found_namespace_decl)); - LLDB_LOGF(log, " CMN[%u] Found namespace %s in module %s", current_id, - name.GetCString(), - image->GetFileSpec().GetFilename().GetCString()); + LLDB_LOG(log, " CMN[{0}] Found namespace {0} in module {1}", name, + image->GetFileSpec().GetFilename()); } } } @@ -1776,11 +1698,11 @@ NamespaceDecl *ClangASTSource::AddNamespace( const CompilerDeclContext &namespace_decl = namespace_decls->begin()->second; clang::ASTContext *src_ast = - ClangASTContext::DeclContextGetClangASTContext(namespace_decl); + TypeSystemClang::DeclContextGetTypeSystemClang(namespace_decl); if (!src_ast) return nullptr; clang::NamespaceDecl *src_namespace_decl = - ClangASTContext::DeclContextGetAsNamespaceDecl(namespace_decl); + TypeSystemClang::DeclContextGetAsNamespaceDecl(namespace_decl); if (!src_namespace_decl) return nullptr; @@ -1804,42 +1726,21 @@ NamespaceDecl *ClangASTSource::AddNamespace( } clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) { - if (m_ast_importer_sp) { - return m_ast_importer_sp->CopyDecl(m_ast_context, src_decl); - } else { - lldbassert(0 && "No mechanism for copying a decl!"); - return nullptr; - } + return m_ast_importer_sp->CopyDecl(m_ast_context, src_decl); } ClangASTImporter::DeclOrigin ClangASTSource::GetDeclOrigin(const clang::Decl *decl) { - if (m_ast_importer_sp) { - return m_ast_importer_sp->GetDeclOrigin(decl); - } else { - // this can happen early enough that no ExternalASTSource is installed. - return ClangASTImporter::DeclOrigin(); - } + return m_ast_importer_sp->GetDeclOrigin(decl); } CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { - ClangASTContext *src_ast = - llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem()); + TypeSystemClang *src_ast = + llvm::dyn_cast_or_null<TypeSystemClang>(src_type.GetTypeSystem()); if (src_ast == nullptr) return CompilerType(); - SetImportInProgress(true); - - QualType copied_qual_type; - - if (m_ast_importer_sp) { - copied_qual_type = ClangUtil::GetQualType( - m_ast_importer_sp->CopyType(*m_clang_ast_context, src_type)); - } else { - lldbassert(0 && "No mechanism for copying a type!"); - return CompilerType(); - } - - SetImportInProgress(false); + QualType copied_qual_type = ClangUtil::GetQualType( + m_ast_importer_sp->CopyType(*m_clang_ast_context, src_type)); if (copied_qual_type.getAsOpaquePtr() && copied_qual_type->getCanonicalTypeInternal().isNull()) @@ -1849,170 +1750,3 @@ CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { return m_clang_ast_context->GetType(copied_qual_type); } - -clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { - assert(type && "Type for variable must be valid!"); - - if (!type.IsValid()) - return nullptr; - - ClangASTContext *lldb_ast = - llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); - if (!lldb_ast) - return nullptr; - - IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); - - clang::ASTContext &ast = lldb_ast->getASTContext(); - - clang::NamedDecl *Decl = VarDecl::Create( - ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), - SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); - m_decls.push_back(Decl); - - return Decl; -} - -clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, - bool extern_c) { - assert(type && "Type for variable must be valid!"); - - if (!type.IsValid()) - return nullptr; - - if (m_function_types.count(type)) - return nullptr; - - ClangASTContext *lldb_ast = - llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem()); - if (!lldb_ast) - return nullptr; - - m_function_types.insert(type); - - QualType qual_type(ClangUtil::GetQualType(type)); - - clang::ASTContext &ast = lldb_ast->getASTContext(); - - const bool isInlineSpecified = false; - const bool hasWrittenPrototype = true; - const bool isConstexprSpecified = false; - - clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context); - - if (extern_c) { - context = LinkageSpecDecl::Create( - ast, context, SourceLocation(), SourceLocation(), - clang::LinkageSpecDecl::LanguageIDs::lang_c, false); - } - - // Pass the identifier info for functions the decl_name is needed for - // operators - clang::DeclarationName decl_name = - m_decl_name.getNameKind() == DeclarationName::Identifier - ? m_decl_name.getAsIdentifierInfo() - : m_decl_name; - - clang::FunctionDecl *func_decl = FunctionDecl::Create( - ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, - nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); - - // We have to do more than just synthesize the FunctionDecl. We have to - // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do - // this, we raid the function's FunctionProtoType for types. - - const FunctionProtoType *func_proto_type = - qual_type.getTypePtr()->getAs<FunctionProtoType>(); - - if (func_proto_type) { - unsigned NumArgs = func_proto_type->getNumParams(); - unsigned ArgIndex; - - SmallVector<ParmVarDecl *, 5> parm_var_decls; - - for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) { - QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); - - parm_var_decls.push_back( - ParmVarDecl::Create(ast, const_cast<DeclContext *>(context), - SourceLocation(), SourceLocation(), nullptr, - arg_qual_type, nullptr, SC_Static, nullptr)); - } - - func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls)); - } else { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - LLDB_LOGF(log, "Function type wasn't a FunctionProtoType"); - } - - // If this is an operator (e.g. operator new or operator==), only insert the - // declaration we inferred from the symbol if we can provide the correct - // number of arguments. We shouldn't really inject random decl(s) for - // functions that are analyzed semantically in a special way, otherwise we - // will crash in clang. - clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; - if (func_proto_type && - ClangASTContext::IsOperator(decl_name.getAsString().c_str(), op_kind)) { - if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount( - false, op_kind, func_proto_type->getNumParams())) - return nullptr; - } - m_decls.push_back(func_decl); - - return func_decl; -} - -clang::NamedDecl *NameSearchContext::AddGenericFunDecl() { - FunctionProtoType::ExtProtoInfo proto_info; - - proto_info.Variadic = true; - - QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType( - m_ast_source.m_ast_context->UnknownAnyTy, // result - ArrayRef<QualType>(), // argument types - proto_info)); - - return AddFunDecl( - m_ast_source.m_clang_ast_context->GetType(generic_function_type), true); -} - -clang::NamedDecl * -NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { - if (ClangUtil::IsClangType(clang_type)) { - QualType qual_type = ClangUtil::GetQualType(clang_type); - - if (const TypedefType *typedef_type = - llvm::dyn_cast<TypedefType>(qual_type)) { - TypedefNameDecl *typedef_name_decl = typedef_type->getDecl(); - - m_decls.push_back(typedef_name_decl); - - return (NamedDecl *)typedef_name_decl; - } else if (const TagType *tag_type = qual_type->getAs<TagType>()) { - TagDecl *tag_decl = tag_type->getDecl(); - - m_decls.push_back(tag_decl); - - return tag_decl; - } else if (const ObjCObjectType *objc_object_type = - qual_type->getAs<ObjCObjectType>()) { - ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface(); - - m_decls.push_back((NamedDecl *)interface_decl); - - return (NamedDecl *)interface_decl; - } - } - return nullptr; -} - -void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) { - for (clang::NamedDecl *decl : result) - m_decls.push_back(decl); -} - -void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) { - m_decls.push_back(decl); -} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 3149b4266b2f..14761fbeb26b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -6,12 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangASTSource_h_ -#define liblldb_ClangASTSource_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H #include <set> -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/NameSearchContext.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "clang/AST/ExternalASTSource.h" @@ -42,7 +43,7 @@ public: /// \param[in] importer /// The ClangASTImporter to use. ClangASTSource(const lldb::TargetSP &target, - const lldb::ClangASTImporterSP &importer); + const std::shared_ptr<ClangASTImporter> &importer); /// Destructor ~ClangASTSource() override; @@ -60,7 +61,7 @@ public: } void MaterializeVisibleDecls(const clang::DeclContext *DC) { return; } - void InstallASTContext(ClangASTContext &ast_context); + void InstallASTContext(TypeSystemClang &ast_context); // // APIs for ExternalASTSource @@ -196,11 +197,6 @@ public: clang::Sema *getSema(); - void SetImportInProgress(bool import_in_progress) { - m_import_in_progress = import_in_progress; - } - bool GetImportInProgress() { return m_import_in_progress; } - void SetLookupsEnabled(bool lookups_enabled) { m_lookups_enabled = lookups_enabled; } @@ -282,14 +278,9 @@ protected: /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, - CompilerDeclContext &namespace_decl, - unsigned int current_id); + CompilerDeclContext &namespace_decl); /// Find all Objective-C methods matching a given selector. /// @@ -307,7 +298,13 @@ protected: /// is the containing object. void FindObjCPropertyAndIvarDecls(NameSearchContext &context); - /// A wrapper for ClangASTContext::CopyType that sets a flag that + /// Performs lookup into a namespace. + /// + /// \param context + /// The NameSearchContext for a lookup inside a namespace. + void LookupInNamespace(NameSearchContext &context); + + /// A wrapper for TypeSystemClang::CopyType that sets a flag that /// indicates that we should not respond to queries during import. /// /// \param[in] src_type @@ -331,7 +328,6 @@ public: /// global lookup for performance reasons. bool IgnoreName(const ConstString name, bool ignore_all_dollar_names); -public: /// Copies a single Decl into the parser's AST context. /// /// \param[in] src_decl @@ -346,139 +342,51 @@ public: /// \param[in] decl /// The Decl whose origin is to be found. /// - /// \param[out] original_decl - /// A pointer whose target is filled in with the original Decl. - /// - /// \param[in] original_ctx - /// A pointer whose target is filled in with the original's ASTContext. - /// /// \return /// True if lookup succeeded; false otherwise. ClangASTImporter::DeclOrigin GetDeclOrigin(const clang::Decl *decl); + /// Returns the TypeSystem that uses this ClangASTSource instance as it's + /// ExternalASTSource. + TypeSystemClang *GetTypeSystem() const { return m_clang_ast_context; } + protected: bool FindObjCMethodDeclsWithOrigin( - unsigned int current_id, NameSearchContext &context, + NameSearchContext &context, clang::ObjCInterfaceDecl *original_interface_decl, const char *log_info); + void FindDeclInModules(NameSearchContext &context, ConstString name); + void FindDeclInObjCRuntime(NameSearchContext &context, ConstString name); + + /// Fills the namespace map of the given NameSearchContext. + /// + /// \param context The NameSearchContext with the namespace map to fill. + /// \param module_sp The module to search for namespaces or a nullptr if + /// the current target should be searched. + /// \param namespace_decl The DeclContext in which to search for namespaces. + void FillNamespaceMap(NameSearchContext &context, lldb::ModuleSP module_sp, + const CompilerDeclContext &namespace_decl); + + clang::TagDecl *FindCompleteType(const clang::TagDecl *decl); + friend struct NameSearchContext; - bool m_import_in_progress; bool m_lookups_enabled; /// The target to use in finding variables and types. const lldb::TargetSP m_target; /// The AST context requests are coming in for. clang::ASTContext *m_ast_context; - /// The ClangASTContext for m_ast_context. - ClangASTContext *m_clang_ast_context; + /// The TypeSystemClang for m_ast_context. + TypeSystemClang *m_clang_ast_context; /// The file manager paired with the AST context. clang::FileManager *m_file_manager; /// The target's AST importer. - lldb::ClangASTImporterSP m_ast_importer_sp; + std::shared_ptr<ClangASTImporter> m_ast_importer_sp; std::set<const clang::Decl *> m_active_lexical_decls; std::set<const char *> m_active_lookups; }; -/// \class NameSearchContext ClangASTSource.h -/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a -/// single name lookup -/// -/// LLDB needs to create Decls for entities it finds. This class communicates -/// what name is being searched for and provides helper functions to construct -/// Decls given appropriate type information. -struct NameSearchContext { - /// The AST source making the request. - ClangASTSource &m_ast_source; - /// The list of declarations already constructed. - llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls; - /// The mapping of all namespaces found for this request back to their - /// modules. - ClangASTImporter::NamespaceMapSP m_namespace_map; - /// The name being looked for. - const clang::DeclarationName &m_decl_name; - /// The DeclContext to put declarations into. - const clang::DeclContext *m_decl_context; - /// All the types of functions that have been reported, so we don't - /// report conflicts. - llvm::SmallSet<CompilerType, 5> m_function_types; - - struct { - bool variable : 1; - bool function_with_type_info : 1; - bool function : 1; - bool local_vars_nsp : 1; - bool type : 1; - } m_found; - - /// Constructor - /// - /// Initializes class variables. - /// - /// \param[in] astSource - /// A reference to the AST source making a request. - /// - /// \param[in] decls - /// A reference to a list into which new Decls will be placed. This - /// list is typically empty when the function is called. - /// - /// \param[in] name - /// The name being searched for (always an Identifier). - /// - /// \param[in] dc - /// The DeclContext to register Decls in. - NameSearchContext(ClangASTSource &astSource, - llvm::SmallVectorImpl<clang::NamedDecl *> &decls, - clang::DeclarationName &name, const clang::DeclContext *dc) - : m_ast_source(astSource), m_decls(decls), m_decl_name(name), - m_decl_context(dc) { - memset(&m_found, 0, sizeof(m_found)); - } - - /// Create a VarDecl with the name being searched for and the provided type - /// and register it in the right places. - /// - /// \param[in] type - /// The opaque QualType for the VarDecl being registered. - clang::NamedDecl *AddVarDecl(const CompilerType &type); - - /// Create a FunDecl with the name being searched for and the provided type - /// and register it in the right places. - /// - /// \param[in] type - /// The opaque QualType for the FunDecl being registered. - /// - /// \param[in] extern_c - /// If true, build an extern "C" linkage specification for this. - clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false); - - /// Create a FunDecl with the name being searched for and generic type (i.e. - /// intptr_t NAME_GOES_HERE(...)) and register it in the right places. - clang::NamedDecl *AddGenericFunDecl(); - - /// Create a TypeDecl with the name being searched for and the provided type - /// and register it in the right places. - /// - /// \param[in] compiler_type - /// The opaque QualType for the TypeDecl being registered. - clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type); - - /// Add Decls from the provided DeclContextLookupResult to the list of - /// results. - /// - /// \param[in] result - /// The DeclContextLookupResult, usually returned as the result - /// of querying a DeclContext. - void AddLookupResult(clang::DeclContextLookupResult result); - - /// Add a NamedDecl to the list of results. - /// - /// \param[in] decl - /// The NamedDecl, usually returned as the result - /// of querying a DeclContext. - void AddNamedDecl(clang::NamedDecl *decl); -}; - } // namespace lldb_private -#endif // liblldb_ClangASTSource_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTSOURCE_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp index c87507a25855..867d4ff0a907 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp @@ -1,4 +1,4 @@ -//===-- ClangDeclVendor.cpp -------------------------------------*- C++ -*-===// +//===-- ClangDeclVendor.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Utility/ConstString.h" using namespace lldb_private; @@ -22,7 +23,7 @@ uint32_t ClangDeclVendor::FindDecls(ConstString name, bool append, std::vector<CompilerDecl> compiler_decls; uint32_t ret = FindDecls(name, /*append*/ false, max_matches, compiler_decls); for (CompilerDecl compiler_decl : compiler_decls) { - clang::Decl *d = static_cast<clang::Decl *>(compiler_decl.GetOpaqueDecl()); + clang::Decl *d = ClangUtil::GetDecl(compiler_decl); clang::NamedDecl *nd = llvm::cast<clang::NamedDecl>(d); decls.push_back(nd); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h index 0c888de08841..bf52bec4b1fa 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h @@ -6,12 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangDeclVendor_h_ -#define liblldb_ClangDeclVendor_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDECLVENDOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDECLVENDOR_H -#include "lldb/Core/ClangForward.h" #include "lldb/Symbol/DeclVendor.h" +namespace clang { +class NamedDecl; +} + namespace lldb_private { // A clang specialized extension to DeclVendor. @@ -32,7 +35,8 @@ public: } private: - DISALLOW_COPY_AND_ASSIGN(ClangDeclVendor); + ClangDeclVendor(const ClangDeclVendor &) = delete; + const ClangDeclVendor &operator=(const ClangDeclVendor &) = delete; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h index 48cd1c4b99fa..7459b715dbe2 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_ClangDiagnostic_h -#define lldb_ClangDiagnostic_h +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H #include <vector> @@ -47,4 +47,4 @@ private: }; } // namespace lldb_private -#endif /* lldb_ClangDiagnostic_h */ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGDIAGNOSTIC_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index bf3023be5f60..8c49898e1d6c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===// +//===-- ClangExpressionDeclMap.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,15 +11,15 @@ #include "ClangASTSource.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" @@ -65,8 +65,8 @@ const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars"; ClangExpressionDeclMap::ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - const lldb::TargetSP &target, const lldb::ClangASTImporterSP &importer, - ValueObject *ctx_obj) + const lldb::TargetSP &target, + const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj) : ClangASTSource(target, importer), m_found_entities(), m_struct_members(), m_keep_result_in_memory(keep_result_in_memory), m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(), @@ -109,7 +109,7 @@ bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>( target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); - if (!ClangASTContext::GetScratch(*target)) + if (!TypeSystemClang::GetScratch(*target)) return false; } @@ -174,19 +174,14 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { return ret; } -TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target, - ClangASTContext &source, +TypeFromUser ClangExpressionDeclMap::DeportType(TypeSystemClang &target, + TypeSystemClang &source, TypeFromParser parser_type) { - assert(&target == ClangASTContext::GetScratch(*m_target)); + assert(&target == TypeSystemClang::GetScratch(*m_target)); 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, parser_type)); - } else { - lldbassert(0 && "No mechanism for deporting a type!"); - return TypeFromUser(); - } + return TypeFromUser(m_ast_importer_sp->DeportType(target, parser_type)); } bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, @@ -196,8 +191,8 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, bool is_lvalue) { assert(m_parser_vars.get()); - ClangASTContext *ast = - llvm::dyn_cast_or_null<ClangASTContext>(parser_type.GetTypeSystem()); + TypeSystemClang *ast = + llvm::dyn_cast_or_null<TypeSystemClang>(parser_type.GetTypeSystem()); if (ast == nullptr) return false; @@ -209,7 +204,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - auto *clang_ast_context = ClangASTContext::GetScratch(*target); + auto *clang_ast_context = TypeSystemClang::GetScratch(*target); if (!clang_ast_context) return false; @@ -231,7 +226,6 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, var->GetParserVars(GetParserID()); parser_vars->m_named_decl = decl; - parser_vars->m_parser_type = parser_type; var->EnableJITVars(GetParserID()); @@ -248,14 +242,14 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - ClangASTContext *context = ClangASTContext::GetScratch(*target); + TypeSystemClang *context = TypeSystemClang::GetScratch(*target); if (!context) return false; TypeFromUser user_type = DeportType(*context, *ast, parser_type); if (!user_type.GetOpaqueQualType()) { - LLDB_LOGF(log, "Persistent variable's type wasn't copied successfully"); + LLDB_LOG(log, "Persistent variable's type wasn't copied successfully"); return false; } @@ -297,7 +291,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, var->m_flags |= ClangExpressionVariable::EVKeepInTarget; } - LLDB_LOGF(log, "Created persistent variable with flags 0x%hx", var->m_flags); + LLDB_LOG(log, "Created persistent variable with flags {0:x}", var->m_flags); var->EnableParserVars(GetParserID()); @@ -305,7 +299,6 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, var->GetParserVars(GetParserID()); parser_vars->m_named_decl = decl; - parser_vars->m_parser_type = parser_type; return true; } @@ -339,9 +332,8 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, if (!var) return false; - LLDB_LOGF(log, "Adding value for (NamedDecl*)%p [%s - %s] to the structure", - static_cast<const void *>(decl), name.GetCString(), - var->GetName().GetCString()); + LLDB_LOG(log, "Adding value for (NamedDecl*)%p [%s - %s] to the structure", + decl, name, var->GetName()); // We know entity->m_parser_vars is valid because we used a parser variable // to find it @@ -355,8 +347,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, llvm::cast<ClangExpressionVariable>(var)->GetJITVars(GetParserID())) { // We already laid this out; do not touch - LLDB_LOGF(log, "Already placed at 0x%llx", - (unsigned long long)jit_vars->m_offset); + LLDB_LOG(log, "Already placed at {0:x}", jit_vars->m_offset); } llvm::cast<ClangExpressionVariable>(var)->EnableJITVars(GetParserID()); @@ -391,7 +382,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, if (!err.Success()) return false; - LLDB_LOGF(log, "Placed at 0x%llx", (unsigned long long)offset); + LLDB_LOG(log, "Placed at {0:x}", offset); jit_vars->m_offset = offset; // TODO DoStructLayout() should not change this. @@ -600,7 +591,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(ConstString name, lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( Target &target, ModuleSP &module, ConstString name, - CompilerDeclContext *namespace_decl) { + const CompilerDeclContext &namespace_decl) { VariableList vars; if (module && namespace_decl) @@ -613,7 +604,7 @@ lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable( return vars.GetVariableAtIndex(0); } -ClangASTContext *ClangExpressionDeclMap::GetClangASTContext() { +TypeSystemClang *ClangExpressionDeclMap::GetTypeSystemClang() { StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); if (frame == nullptr) return nullptr; @@ -627,7 +618,7 @@ ClangASTContext *ClangExpressionDeclMap::GetClangASTContext() { if (!frame_decl_context) return nullptr; - return llvm::dyn_cast_or_null<ClangASTContext>( + return llvm::dyn_cast_or_null<TypeSystemClang>( frame_decl_context.GetTypeSystem()); } @@ -641,34 +632,23 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (GetImportInProgress()) { - if (log && log->GetVerbose()) - LLDB_LOGF(log, "Ignoring a query during an import"); - return; - } - - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - if (log) { if (!context.m_decl_context) - LLDB_LOGF(log, - "ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " - "'%s' in a NULL DeclContext", - current_id, name.GetCString()); + LLDB_LOG(log, + "ClangExpressionDeclMap::FindExternalVisibleDecls for " + "'{0}' in a NULL DeclContext", + name); else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context)) - LLDB_LOGF(log, - "ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " - "'%s' in '%s'", - current_id, name.GetCString(), - context_named_decl->getNameAsString().c_str()); + LLDB_LOG(log, + "ClangExpressionDeclMap::FindExternalVisibleDecls for " + "'{0}' in '{1}'", + name, context_named_decl->getNameAsString()); else - LLDB_LOGF(log, - "ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for " - "'%s' in a '%s'", - current_id, name.GetCString(), - context.m_decl_context->getDeclKindName()); + LLDB_LOG(log, + "ClangExpressionDeclMap::FindExternalVisibleDecls for " + "'{0}' in a '{1}'", + name, context.m_decl_context->getDeclKindName()); } if (const NamespaceDecl *namespace_context = @@ -678,42 +658,31 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( CompilerDeclContext compiler_decl_ctx = m_clang_ast_context->CreateDeclContext( const_cast<clang::DeclContext *>(context.m_decl_context)); - FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx, - current_id); + FindExternalVisibleDecls(context, lldb::ModuleSP(), compiler_decl_ctx); return; } ClangASTImporter::NamespaceMapSP namespace_map = - m_ast_importer_sp - ? m_ast_importer_sp->GetNamespaceMap(namespace_context) - : ClangASTImporter::NamespaceMapSP(); + m_ast_importer_sp->GetNamespaceMap(namespace_context); 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()); + LLDB_LOGV(log, " CEDM::FEVD Inspecting (NamespaceMap*){0:x} ({1} entries)", + namespace_map.get(), namespace_map->size()); - for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), - e = namespace_map->end(); - i != e; ++i) { - if (log) - log->Printf(" CEDM::FEVD[%u] Searching namespace %s in module %s", - current_id, i->second.GetName().AsCString(), - i->first->GetFileSpec().GetFilename().GetCString()); + for (ClangASTImporter::NamespaceMapItem &n : *namespace_map) { + LLDB_LOG(log, " CEDM::FEVD Searching namespace {0} in module {1}", + n.second.GetName(), n.first->GetFileSpec().GetFilename()); - FindExternalVisibleDecls(context, i->first, i->second, current_id); + FindExternalVisibleDecls(context, n.first, n.second); } } else if (isa<TranslationUnitDecl>(context.m_decl_context)) { CompilerDeclContext namespace_decl; - if (log) - log->Printf(" CEDM::FEVD[%u] Searching the root namespace", current_id); + LLDB_LOG(log, " CEDM::FEVD Searching the root namespace"); - FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl, - current_id); + FindExternalVisibleDecls(context, lldb::ModuleSP(), namespace_decl); } ClangASTSource::FindExternalVisibleDecls(context); @@ -734,7 +703,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { if (!target) return nullptr; - ClangASTContext::GetScratch(*target); + TypeSystemClang::GetScratch(*target); if (!m_parser_vars->m_persistent_vars) return nullptr; @@ -742,8 +711,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { } void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context, - const ConstString name, - unsigned int current_id) { + const ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); NamedDecl *persistent_decl = GetPersistentDecl(name); @@ -766,14 +734,12 @@ void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context, MaybeRegisterFunctionBody(parser_function_decl); } - LLDB_LOGF(log, " CEDM::FEVD[%u] Found persistent decl %s", current_id, - name.GetCString()); + LLDB_LOG(log, " CEDM::FEVD Found persistent decl %s", name); context.AddNamedDecl(parser_named_decl); } -void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, - unsigned int current_id) { +void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); @@ -788,8 +754,7 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, if (!ctx_obj_ptr || status.Fail()) return; - AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), - current_id); + AddContextClassType(context, TypeFromUser(m_ctx_obj->GetCompilerType())); m_struct_vars->m_object_pointer_type = TypeFromUser(ctx_obj_ptr->GetCompilerType()); @@ -814,7 +779,7 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, return; clang::CXXMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsCXXMethodDecl(function_decl_ctx); + TypeSystemClang::DeclContextGetAsCXXMethodDecl(function_decl_ctx); if (method_decl) { clang::CXXRecordDecl *class_decl = method_decl->getParent(); @@ -824,10 +789,10 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, TypeFromUser class_user_type(class_qual_type.getAsOpaquePtr(), function_decl_ctx.GetTypeSystem()); - LLDB_LOG(log, " CEDM::FEVD[{0}] Adding type for $__lldb_class: {1}", - current_id, class_qual_type.getAsString()); + LLDB_LOG(log, " CEDM::FEVD Adding type for $__lldb_class: {1}", + class_qual_type.getAsString()); - AddThisType(context, class_user_type, current_id); + AddContextClassType(context, class_user_type); if (method_decl->isInstance()) { // self is a pointer to the object @@ -866,17 +831,16 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context, TypeFromUser pointee_type = this_type->GetForwardCompilerType().GetPointeeType(); - LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_class: {1}", current_id, + LLDB_LOG(log, " FEVD Adding type for $__lldb_class: {1}", ClangUtil::GetQualType(pointee_type).getAsString()); - AddThisType(context, pointee_type, current_id); + AddContextClassType(context, pointee_type); TypeFromUser this_user_type(this_type->GetFullCompilerType()); m_struct_vars->m_object_pointer_type = this_user_type; } } -void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, - unsigned int current_id) { +void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr(); @@ -887,7 +851,7 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, if (!ctx_obj_ptr || status.Fail()) return; - AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()), current_id); + AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType())); m_struct_vars->m_object_pointer_type = TypeFromUser(ctx_obj_ptr->GetCompilerType()); @@ -915,7 +879,7 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, return; clang::ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl(function_decl_ctx); + TypeSystemClang::DeclContextGetAsObjCMethodDecl(function_decl_ctx); if (method_decl) { ObjCInterfaceDecl *self_interface = method_decl->getClassInterface(); @@ -933,9 +897,9 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, function_decl_ctx.GetTypeSystem()); LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}", - current_id, ClangUtil::ToString(interface_type)); + ClangUtil::ToString(interface_type)); - AddOneType(context, class_user_type, current_id); + AddOneType(context, class_user_type); if (method_decl->isInstanceMethod()) { // self is a pointer to the object @@ -984,10 +948,10 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, CompilerType self_clang_type = self_type->GetFullCompilerType(); - if (ClangASTContext::IsObjCClassType(self_clang_type)) { + if (TypeSystemClang::IsObjCClassType(self_clang_type)) { return; } - if (!ClangASTContext::IsObjCObjectPointerType(self_clang_type)) + if (!TypeSystemClang::IsObjCObjectPointerType(self_clang_type)) return; self_clang_type = self_clang_type.GetPointeeType(); @@ -995,11 +959,11 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context, return; LLDB_LOG(log, " FEVD[{0}] Adding type for $__lldb_objc_class: {1}", - current_id, ClangUtil::ToString(self_type->GetFullCompilerType())); + ClangUtil::ToString(self_type->GetFullCompilerType())); TypeFromUser class_user_type(self_clang_type); - AddOneType(context, class_user_type, current_id); + AddOneType(context, class_user_type); TypeFromUser self_user_type(self_type->GetFullCompilerType()); @@ -1015,25 +979,25 @@ void ClangExpressionDeclMap::LookupLocalVarNamespace( if (!frame_decl_context) return; - ClangASTContext *frame_ast = llvm::dyn_cast_or_null<ClangASTContext>( + TypeSystemClang *frame_ast = llvm::dyn_cast_or_null<TypeSystemClang>( frame_decl_context.GetTypeSystem()); if (!frame_ast) return; clang::NamespaceDecl *namespace_decl = m_clang_ast_context->GetUniqueNamespaceDeclaration( - g_lldb_local_vars_namespace_cstr, nullptr); + g_lldb_local_vars_namespace_cstr, nullptr, OptionalClangModuleID()); if (!namespace_decl) return; name_context.AddNamedDecl(namespace_decl); clang::DeclContext *ctxt = clang::Decl::castToDeclContext(namespace_decl); ctxt->setHasExternalVisibleStorage(true); - name_context.m_found.local_vars_nsp = true; + name_context.m_found_local_vars_nsp = true; } void ClangExpressionDeclMap::LookupInModulesDeclVendor( - NameSearchContext &context, ConstString name, unsigned current_id) { + NameSearchContext &context, ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (!m_target) @@ -1054,16 +1018,14 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor( clang::NamedDecl *const decl_from_modules = decls[0]; LLDB_LOG(log, - " CAS::FEVD[{0}] Matching decl found for " + " CAS::FEVD Matching decl found for " "\"{1}\" in the modules", - current_id, name); + name); clang::Decl *copied_decl = CopyDecl(decl_from_modules); if (!copied_decl) { - LLDB_LOG(log, - " CAS::FEVD[{0}] - Couldn't export a " - "declaration from the modules", - current_id); + LLDB_LOG(log, " CAS::FEVD - Couldn't export a " + "declaration from the modules"); return; } @@ -1072,17 +1034,17 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor( context.AddNamedDecl(copied_function); - context.m_found.function_with_type_info = true; - context.m_found.function = true; + context.m_found_function_with_type_info = true; + context.m_found_function = true; } else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) { context.AddNamedDecl(copied_var); - context.m_found.variable = true; + context.m_found_variable = true; } } bool ClangExpressionDeclMap::LookupLocalVariable( - NameSearchContext &context, ConstString name, unsigned current_id, - SymbolContext &sym_ctx, CompilerDeclContext &namespace_decl) { + NameSearchContext &context, ConstString name, SymbolContext &sym_ctx, + const CompilerDeclContext &namespace_decl) { if (sym_ctx.block == nullptr) return false; @@ -1117,8 +1079,8 @@ bool ClangExpressionDeclMap::LookupLocalVariable( if (var && !variable_found) { variable_found = true; ValueObjectSP valobj = ValueObjectVariable::Create(frame, var); - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; + AddOneVariable(context, var, valobj); + context.m_found_variable = true; } } return variable_found; @@ -1148,7 +1110,7 @@ SymbolContextList ClangExpressionDeclMap::SearchFunctionsInSymbolContexts( decl_infos.reserve(num_indices); clang::DeclContext *frame_decl_ctx = (clang::DeclContext *)frame_decl_context.GetOpaqueDeclContext(); - ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>( + TypeSystemClang *ast = llvm::dyn_cast_or_null<TypeSystemClang>( frame_decl_context.GetTypeSystem()); for (uint32_t index = 0; index < num_indices; ++index) { @@ -1222,11 +1184,9 @@ SymbolContextList ClangExpressionDeclMap::SearchFunctionsInSymbolContexts( return sc_func_list; } -void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, - lldb::ModuleSP module_sp, - ConstString name, - CompilerDeclContext &namespace_decl, - unsigned current_id) { +void ClangExpressionDeclMap::LookupFunction( + NameSearchContext &context, lldb::ModuleSP module_sp, ConstString name, + const CompilerDeclContext &namespace_decl) { if (!m_parser_vars) return; @@ -1246,7 +1206,7 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, if (namespace_decl && module_sp) { const bool include_symbols = false; - module_sp->FindFunctions(name, &namespace_decl, eFunctionNameTypeBase, + module_sp->FindFunctions(name, namespace_decl, eFunctionNameTypeBase, include_symbols, include_inlines, sc_list); } else if (target && !namespace_decl) { const bool include_symbols = true; @@ -1304,9 +1264,9 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr)) continue; - AddOneFunction(context, sym_ctx.function, nullptr, current_id); - context.m_found.function_with_type_info = true; - context.m_found.function = true; + AddOneFunction(context, sym_ctx.function, nullptr); + context.m_found_function_with_type_info = true; + context.m_found_function = true; } else if (sym_ctx.symbol) { if (sym_ctx.symbol->GetType() == eSymbolTypeReExported && target) { sym_ctx.symbol = sym_ctx.symbol->ResolveReExportedSymbol(*target); @@ -1321,26 +1281,26 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, } } - if (!context.m_found.function_with_type_info) { + if (!context.m_found_function_with_type_info) { for (clang::NamedDecl *decl : decls_from_modules) { if (llvm::isa<clang::FunctionDecl>(decl)) { clang::NamedDecl *copied_decl = llvm::cast_or_null<FunctionDecl>(CopyDecl(decl)); if (copied_decl) { context.AddNamedDecl(copied_decl); - context.m_found.function_with_type_info = true; + context.m_found_function_with_type_info = true; } } } } - if (!context.m_found.function_with_type_info) { + if (!context.m_found_function_with_type_info) { if (extern_symbol) { - AddOneFunction(context, nullptr, extern_symbol, current_id); - context.m_found.function = true; + AddOneFunction(context, nullptr, extern_symbol); + context.m_found_function = true; } else if (non_extern_symbol) { - AddOneFunction(context, nullptr, non_extern_symbol, current_id); - context.m_found.function = true; + AddOneFunction(context, nullptr, non_extern_symbol); + context.m_found_function = true; } } } @@ -1348,7 +1308,7 @@ void ClangExpressionDeclMap::LookupFunction(NameSearchContext &context, void ClangExpressionDeclMap::FindExternalVisibleDecls( NameSearchContext &context, lldb::ModuleSP module_sp, - CompilerDeclContext &namespace_decl, unsigned int current_id) { + const CompilerDeclContext &namespace_decl) { assert(m_ast_context); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1373,16 +1333,16 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( // Try the persistent decls, which take precedence over all else. if (!namespace_decl) - SearchPersistenDecls(context, name, current_id); + SearchPersistenDecls(context, name); if (name.GetStringRef().startswith("$") && !namespace_decl) { if (name == "$__lldb_class") { - LookUpLldbClass(context, current_id); + LookUpLldbClass(context); return; } if (name == "$__lldb_objc_class") { - LookUpLldbObjCClass(context, current_id); + LookUpLldbObjCClass(context); return; } if (name == g_lldb_local_vars_namespace_cstr) { @@ -1402,7 +1362,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( m_parser_vars->m_persistent_vars->GetVariable(name)); if (pvar_sp) { - AddOneVariable(context, pvar_sp, current_id); + AddOneVariable(context, pvar_sp); return; } @@ -1415,10 +1375,9 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( reg_name)); if (reg_info) { - LLDB_LOGF(log, " CEDM::FEVD[%u] Found register %s", current_id, - reg_info->name); + LLDB_LOG(log, " CEDM::FEVD Found register {0}", reg_info->name); - AddOneRegister(context, reg_info, current_id); + AddOneRegister(context, reg_info); } } return; @@ -1427,29 +1386,29 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( bool local_var_lookup = !namespace_decl || (namespace_decl.GetName() == g_lldb_local_vars_namespace_cstr); if (frame && local_var_lookup) - if (LookupLocalVariable(context, name, current_id, sym_ctx, namespace_decl)) + if (LookupLocalVariable(context, name, sym_ctx, namespace_decl)) return; if (target) { ValueObjectSP valobj; VariableSP var; - var = FindGlobalVariable(*target, module_sp, name, &namespace_decl); + var = FindGlobalVariable(*target, module_sp, name, namespace_decl); if (var) { valobj = ValueObjectVariable::Create(target, var); - AddOneVariable(context, var, valobj, current_id); - context.m_found.variable = true; + AddOneVariable(context, var, valobj); + context.m_found_variable = true; return; } } - LookupFunction(context, module_sp, name, namespace_decl, current_id); + LookupFunction(context, module_sp, name, namespace_decl); // Try the modules next. - if (!context.m_found.function_with_type_info) - LookupInModulesDeclVendor(context, name, current_id); + if (!context.m_found_function_with_type_info) + LookupInModulesDeclVendor(context, name); - if (target && !context.m_found.variable && !namespace_decl) { + if (target && !context.m_found_variable && !namespace_decl) { // We couldn't find a non-symbol variable for this. Now we'll hunt for a // generic data symbol, and -- if it is found -- treat it as a variable. Status error; @@ -1471,8 +1430,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls( m_ast_context->getDiagnostics().getCustomDiagID( clang::DiagnosticsEngine::Level::Warning, "%0"); m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); - AddOneGenericVariable(context, *data_symbol, current_id); - context.m_found.variable = true; + AddOneGenericVariable(context, *data_symbol); + context.m_found_variable = true; } } } @@ -1486,25 +1445,22 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, Type *var_type = var->GetType(); if (!var_type) { - if (log) - log->PutCString("Skipped a definition because it has no type"); + LLDB_LOG(log, "Skipped a definition because it has no type"); return false; } CompilerType var_clang_type = var_type->GetFullCompilerType(); if (!var_clang_type) { - if (log) - log->PutCString("Skipped a definition because it has no Clang type"); + LLDB_LOG(log, "Skipped a definition because it has no Clang type"); return false; } - ClangASTContext *clang_ast = llvm::dyn_cast_or_null<ClangASTContext>( + TypeSystemClang *clang_ast = llvm::dyn_cast_or_null<TypeSystemClang>( var_type->GetForwardCompilerType().GetTypeSystem()); if (!clang_ast) { - if (log) - log->PutCString("Skipped a definition because it has no Clang AST"); + LLDB_LOG(log, "Skipped a definition because it has no Clang AST"); return false; } @@ -1521,7 +1477,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, const_value_extractor.GetByteSize()); var_location.SetValueType(Value::eValueTypeHostAddress); } else { - LLDB_LOGF(log, "Error evaluating constant variable: %s", err.AsCString()); + LLDB_LOG(log, "Error evaluating constant variable: {0}", err.AsCString()); return false; } } @@ -1529,8 +1485,8 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, CompilerType type_to_use = GuardedCopyType(var_clang_type); if (!type_to_use) { - LLDB_LOGF(log, - "Couldn't copy a variable's type into the parser's AST context"); + LLDB_LOG(log, + "Couldn't copy a variable's type into the parser's AST context"); return false; } @@ -1567,8 +1523,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, VariableSP var, - ValueObjectSP valobj, - unsigned int current_id) { + ValueObjectSP valobj) { assert(m_parser_vars.get()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1611,7 +1566,6 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, entity->EnableParserVars(GetParserID()); ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID()); - parser_vars->m_parser_type = pt; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value = var_location; @@ -1620,15 +1574,12 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, if (is_reference) entity->m_flags |= ClangExpressionVariable::EVTypeIsReference; - LLDB_LOG(log, - " CEDM::FEVD[{0}] Found variable {1}, returned\n{2} (original {3})", - current_id, decl_name, ClangUtil::DumpDecl(var_decl), - ClangUtil::ToString(ut)); + LLDB_LOG(log, " CEDM::FEVD Found variable {1}, returned\n{2} (original {3})", + decl_name, ClangUtil::DumpDecl(var_decl), ClangUtil::ToString(ut)); } void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, - ExpressionVariableSP &pvar_sp, - unsigned int current_id) { + ExpressionVariableSP &pvar_sp) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); TypeFromUser user_type( @@ -1637,8 +1588,8 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, TypeFromParser parser_type(GuardedCopyType(user_type)); if (!parser_type.GetOpaqueQualType()) { - LLDB_LOGF(log, " CEDM::FEVD[%u] Couldn't import type for pvar %s", - current_id, pvar_sp->GetName().GetCString()); + LLDB_LOG(log, " CEDM::FEVD Couldn't import type for pvar {0}", + pvar_sp->GetName()); return; } @@ -1650,18 +1601,16 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, ClangExpressionVariable::ParserVars *parser_vars = llvm::cast<ClangExpressionVariable>(pvar_sp.get()) ->GetParserVars(GetParserID()); - parser_vars->m_parser_type = parser_type; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); - LLDB_LOG(log, " CEDM::FEVD[{0}] Added pvar {1}, returned\n{2}", current_id, + LLDB_LOG(log, " CEDM::FEVD Added pvar {1}, returned\n{2}", pvar_sp->GetName(), ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, - const Symbol &symbol, - unsigned int current_id) { + const Symbol &symbol) { assert(m_parser_vars.get()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1671,7 +1620,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, if (target == nullptr) return; - ClangASTContext *scratch_ast_context = ClangASTContext::GetScratch(*target); + TypeSystemClang *scratch_ast_context = TypeSystemClang::GetScratch(*target); if (!scratch_ast_context) return; @@ -1704,18 +1653,16 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, parser_vars->m_lldb_value.GetScalar() = symbol_load_addr; parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress); - parser_vars->m_parser_type = parser_type; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_sym = &symbol; - LLDB_LOG(log, " CEDM::FEVD[{0}] Found variable {1}, returned\n{2}", - current_id, decl_name, ClangUtil::DumpDecl(var_decl)); + LLDB_LOG(log, " CEDM::FEVD Found variable {1}, returned\n{2}", decl_name, + ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, - const RegisterInfo *reg_info, - unsigned int current_id) { + const RegisterInfo *reg_info) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); CompilerType clang_type = @@ -1723,8 +1670,8 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, reg_info->encoding, reg_info->byte_size * 8); if (!clang_type) { - LLDB_LOGF(log, " Tried to add a type for %s, but couldn't get one", - context.m_decl_name.getAsString().c_str()); + LLDB_LOG(log, " Tried to add a type for {0}, but couldn't get one", + context.m_decl_name.getAsString()); return; } @@ -1744,20 +1691,18 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context, entity->EnableParserVars(GetParserID()); ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID()); - parser_vars->m_parser_type = parser_clang_type; parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; parser_vars->m_lldb_value.Clear(); entity->m_flags |= ClangExpressionVariable::EVBareRegister; - LLDB_LOG(log, " CEDM::FEVD[{0}] Added register {1}, returned\n{2}", - current_id, context.m_decl_name.getAsString(), - ClangUtil::DumpDecl(var_decl)); + LLDB_LOG(log, " CEDM::FEVD Added register {1}, returned\n{2}", + context.m_decl_name.getAsString(), ClangUtil::DumpDecl(var_decl)); } void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, - Function *function, Symbol *symbol, - unsigned int current_id) { + Function *function, + Symbol *symbol) { assert(m_parser_vars.get()); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1780,7 +1725,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, if (!extern_c) { TypeSystem *type_system = function->GetDeclContext().GetTypeSystem(); - if (llvm::isa<ClangASTContext>(type_system)) { + if (llvm::isa<TypeSystemClang>(type_system)) { clang::DeclContext *src_decl_context = (clang::DeclContext *)function->GetDeclContext() .GetOpaqueDeclContext(); @@ -1800,9 +1745,9 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function->DumpSymbolContext(&ss); LLDB_LOG(log, - " CEDM::FEVD[{0}] Imported decl for function template" + " CEDM::FEVD Imported decl for function template" " {1} (description {2}), returned\n{3}", - current_id, copied_function_template->getNameAsString(), + copied_function_template->getNameAsString(), ss.GetData(), ClangUtil::DumpDecl(copied_function_template)); } @@ -1819,35 +1764,31 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function->DumpSymbolContext(&ss); LLDB_LOG(log, - " CEDM::FEVD[{0}]] Imported decl for function {1} " + " CEDM::FEVD Imported decl for function {1} " "(description {2}), returned\n{3}", - current_id, copied_function_decl->getNameAsString(), - ss.GetData(), ClangUtil::DumpDecl(copied_function_decl)); + copied_function_decl->getNameAsString(), ss.GetData(), + ClangUtil::DumpDecl(copied_function_decl)); } context.AddNamedDecl(copied_function_decl); return; } else { - if (log) { - LLDB_LOGF(log, " Failed to import the function decl for '%s'", - src_function_decl->getName().str().c_str()); - } + LLDB_LOG(log, " Failed to import the function decl for '{0}'", + src_function_decl->getName()); } } } } if (!function_type) { - if (log) - log->PutCString(" Skipped a function because it has no type"); + LLDB_LOG(log, " Skipped a function because it has no type"); return; } function_clang_type = function_type->GetFullCompilerType(); if (!function_clang_type) { - if (log) - log->PutCString(" Skipped a function because it has no Clang type"); + LLDB_LOG(log, " Skipped a function because it has no Clang type"); return; } @@ -1858,24 +1799,17 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function_decl = context.AddFunDecl(copied_function_type, extern_c); if (!function_decl) { - if (log) { - LLDB_LOGF( - log, - " Failed to create a function decl for '%s' {0x%8.8" PRIx64 "}", - function_type->GetName().GetCString(), function_type->GetID()); - } + LLDB_LOG(log, " Failed to create a function decl for '{0}' ({1:x})", + function_type->GetName(), function_type->GetID()); return; } } else { // We failed to copy the type we found - if (log) { - LLDB_LOGF(log, - " Failed to import the function type '%s' {0x%8.8" PRIx64 - "} into the expression parser AST contenxt", - function_type->GetName().GetCString(), - function_type->GetID()); - } + LLDB_LOG(log, + " Failed to import the function type '{0}' ({1:x})" + " into the expression parser AST contenxt", + function_type->GetName(), function_type->GetID()); return; } @@ -1884,8 +1818,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, function_decl = context.AddGenericFunDecl(); is_indirect_function = symbol->IsIndirect(); } else { - if (log) - log->PutCString(" AddOneFunction called with no function and no symbol"); + LLDB_LOG(log, " AddOneFunction called with no function and no symbol"); return; } @@ -1931,25 +1864,22 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, Address::DumpStyleResolvedDescription); LLDB_LOG(log, - " CEDM::FEVD[{0}] Found {1} function {2} (description {3}), " + " CEDM::FEVD Found {1} function {2} (description {3}), " "returned\n{4}", - current_id, (function ? "specific" : "generic"), decl_name, - ss.GetData(), ClangUtil::DumpDecl(function_decl)); + (function ? "specific" : "generic"), decl_name, ss.GetData(), + ClangUtil::DumpDecl(function_decl)); } } -void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, - const TypeFromUser &ut, - unsigned int current_id) { +void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context, + const TypeFromUser &ut) { CompilerType copied_clang_type = GuardedCopyType(ut); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); if (!copied_clang_type) { - if (log) - LLDB_LOGF( - log, - "ClangExpressionDeclMap::AddThisType - Couldn't import the type"); + LLDB_LOG(log, + "ClangExpressionDeclMap::AddThisType - Couldn't import the type"); return; } @@ -2009,16 +1939,14 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context, } void ClangExpressionDeclMap::AddOneType(NameSearchContext &context, - const TypeFromUser &ut, - unsigned int current_id) { + const TypeFromUser &ut) { CompilerType copied_clang_type = GuardedCopyType(ut); if (!copied_clang_type) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - if (log) - LLDB_LOGF( - log, "ClangExpressionDeclMap::AddOneType - Couldn't import the type"); + LLDB_LOG(log, + "ClangExpressionDeclMap::AddOneType - Couldn't import the type"); return; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 722f5e15a2aa..6974535a8993 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionDeclMap_h_ -#define liblldb_ClangExpressionDeclMap_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H #include <signal.h> #include <stdint.h> @@ -17,7 +17,6 @@ #include "ClangASTSource.h" #include "ClangExpressionVariable.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/SymbolContext.h" @@ -29,6 +28,8 @@ namespace lldb_private { +class ClangPersistentVariables; + /// \class ClangExpressionDeclMap ClangExpressionDeclMap.h /// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are /// defined in LLDB's debug information. @@ -79,8 +80,8 @@ public: ClangExpressionDeclMap( bool keep_result_in_memory, Materializer::PersistentVariableDelegate *result_delegate, - const lldb::TargetSP &target, const lldb::ClangASTImporterSP &importer, - ValueObject *ctx_obj); + const lldb::TargetSP &target, + const std::shared_ptr<ClangASTImporter> &importer, ValueObject *ctx_obj); /// Destructor ~ClangExpressionDeclMap() override; @@ -274,14 +275,9 @@ public: /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. void FindExternalVisibleDecls(NameSearchContext &context, lldb::ModuleSP module, - CompilerDeclContext &namespace_decl, - unsigned int current_id); + const CompilerDeclContext &namespace_decl); protected: /// Retrieves the declaration with the given name from the storage of @@ -335,7 +331,8 @@ private: ///that receives new top-level ///functions. private: - DISALLOW_COPY_AND_ASSIGN(ParserVars); + ParserVars(const ParserVars &) = delete; + const ParserVars &operator=(const ParserVars &) = delete; }; std::unique_ptr<ParserVars> m_parser_vars; @@ -394,32 +391,19 @@ private: /// /// \param[in] name /// The name of the entities that need to be found. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void SearchPersistenDecls(NameSearchContext &context, const ConstString name, - unsigned int current_id); + void SearchPersistenDecls(NameSearchContext &context, const ConstString name); /// Handles looking up $__lldb_class which requires special treatment. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void LookUpLldbClass(NameSearchContext &context, unsigned int current_id); + void LookUpLldbClass(NameSearchContext &context); /// Handles looking up $__lldb_objc_class which requires special treatment. /// /// \param[in] context /// The NameSearchContext that can construct Decls for this name. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void LookUpLldbObjCClass(NameSearchContext &context, unsigned int current_id); + void LookUpLldbObjCClass(NameSearchContext &context); /// Handles looking up the synthetic namespace that contains our local /// variables for the current frame. @@ -438,12 +422,7 @@ private: /// /// \param[in] name /// The name of the entities that need to be found. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name, - unsigned current_id); + void LookupInModulesDeclVendor(NameSearchContext &context, ConstString name); /// Looks up a local variable. /// @@ -453,10 +432,6 @@ private: /// \param[in] name /// The name of the entities that need to be found. /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. - /// /// \param[in] sym_ctx /// The current SymbolContext of this frame. /// @@ -466,8 +441,8 @@ private: /// \return /// True iff a local variable was found. bool LookupLocalVariable(NameSearchContext &context, ConstString name, - unsigned current_id, SymbolContext &sym_ctx, - CompilerDeclContext &namespace_decl); + SymbolContext &sym_ctx, + const CompilerDeclContext &namespace_decl); /// Searches for functions in the given SymbolContextList. /// @@ -499,13 +474,9 @@ private: /// /// \param[in] namespace_decl /// If valid and module is non-NULL, the parent namespace. - /// - /// \param[in] current_id - /// The ID for the current FindExternalVisibleDecls invocation, - /// for logging purposes. void LookupFunction(NameSearchContext &context, lldb::ModuleSP module_sp, - ConstString name, CompilerDeclContext &namespace_decl, - unsigned current_id); + ConstString name, + const CompilerDeclContext &namespace_decl); /// Given a target, find a variable that matches the given name and type. /// @@ -523,9 +494,9 @@ private: /// /// \return /// The LLDB Variable found, or NULL if none was found. - lldb::VariableSP FindGlobalVariable(Target &target, lldb::ModuleSP &module, - ConstString name, - CompilerDeclContext *namespace_decl); + lldb::VariableSP + FindGlobalVariable(Target &target, lldb::ModuleSP &module, ConstString name, + const CompilerDeclContext &namespace_decl); /// Get the value of a variable in a given execution context and return the /// associated Types if needed. @@ -565,7 +536,7 @@ private: /// \param[in] valobj /// The LLDB ValueObject for that variable. void AddOneVariable(NameSearchContext &context, lldb::VariableSP var, - lldb::ValueObjectSP valobj, unsigned int current_id); + lldb::ValueObjectSP valobj); /// Use the NameSearchContext to generate a Decl for the given persistent /// variable, and put it in the list of found entities. @@ -575,18 +546,12 @@ private: /// /// \param[in] pvar_sp /// The persistent variable that needs a Decl. - /// - /// \param[in] current_id - /// The ID of the current invocation of FindExternalVisibleDecls - /// for logging purposes. void AddOneVariable(NameSearchContext &context, - lldb::ExpressionVariableSP &pvar_sp, - unsigned int current_id); + lldb::ExpressionVariableSP &pvar_sp); /// Use the NameSearchContext to generate a Decl for the given LLDB symbol /// (treated as a variable), and put it in the list of found entities. - void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol, - unsigned int current_id); + void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol); /// Use the NameSearchContext to generate a Decl for the given function. /// (Functions are not placed in the Tuple list.) Can handle both fully @@ -602,8 +567,7 @@ private: /// \param[in] sym /// The Symbol that corresponds to a function that needs to be /// created with generic type (unitptr_t foo(...)). - void AddOneFunction(NameSearchContext &context, Function *fun, Symbol *sym, - unsigned int current_id); + void AddOneFunction(NameSearchContext &context, Function *fun, Symbol *sym); /// Use the NameSearchContext to generate a Decl for the given register. /// @@ -612,8 +576,7 @@ private: /// /// \param[in] reg_info /// The information corresponding to that register. - void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info, - unsigned int current_id); + void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info); /// Use the NameSearchContext to generate a Decl for the given type. (Types /// are not placed in the Tuple list.) @@ -623,38 +586,40 @@ private: /// /// \param[in] type /// The type that needs to be created. - void AddOneType(NameSearchContext &context, const TypeFromUser &type, - unsigned int current_id); + void AddOneType(NameSearchContext &context, const TypeFromUser &type); - /// Generate a Decl for "*this" and add a member function declaration to it - /// for the expression, then report it. + /// Adds the class in which the expression is evaluated to the lookup and + /// prepares the class to be used as a context for expression evaluation (for + /// example, it creates a fake member function that will contain the + /// expression LLDB is trying to evaluate). /// /// \param[in] context - /// The NameSearchContext to use when constructing the Decl. + /// The NameSearchContext to which the class should be added as a lookup + /// result. /// /// \param[in] type - /// The type for *this. - void AddThisType(NameSearchContext &context, const TypeFromUser &type, - unsigned int current_id); + /// The type of the class that serves as the evaluation context. + void AddContextClassType(NameSearchContext &context, + const TypeFromUser &type); /// Move a type out of the current ASTContext into another, but make sure to /// export all components of the type also. /// /// \param[in] target - /// The ClangASTContext to move to. + /// The TypeSystemClang to move to. /// \param[in] source - /// The ClangASTContext to move from. This is assumed to be going away. + /// The TypeSystemClang to move from. This is assumed to be going away. /// \param[in] parser_type /// The type as it appears in the source context. /// /// \return /// Returns the moved type, or an empty type if there was a problem. - TypeFromUser DeportType(ClangASTContext &target, ClangASTContext &source, + TypeFromUser DeportType(TypeSystemClang &target, TypeSystemClang &source, TypeFromParser parser_type); - ClangASTContext *GetClangASTContext(); + TypeSystemClang *GetTypeSystemClang(); }; } // namespace lldb_private -#endif // liblldb_ClangExpressionDeclMap_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index 48da5abb9126..e33e5df22236 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -6,21 +6,24 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpression_h_ -#define liblldb_ClangExpression_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H #include <map> #include <string> #include <vector> - -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/ExpressionTypeSystemHelper.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" +namespace clang { +class ASTConsumer; +} + namespace lldb_private { +class ClangExpressionDeclMap; class RecordingMemoryManager; // ClangExpressionHelper @@ -57,4 +60,4 @@ protected: } // namespace lldb_private -#endif // liblldb_ClangExpression_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONHELPER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 8abd14942885..6ff028cf6980 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===// +//===-- ClangExpressionParser.cpp -----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -67,6 +67,7 @@ #include "IRForTarget.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" @@ -75,7 +76,6 @@ #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Language.h" @@ -91,6 +91,7 @@ #include "lldb/Utility/StringList.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h" #include <cctype> #include <memory> @@ -146,21 +147,40 @@ public: llvm::StringRef getErrorString() { return m_error_stream.GetString(); } }; +static void AddAllFixIts(ClangDiagnostic *diag, const clang::Diagnostic &Info) { + for (auto &fix_it : Info.getFixItHints()) { + if (fix_it.isNull()) + continue; + diag->AddFixitHint(fix_it); + } +} + class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer { public: ClangDiagnosticManagerAdapter(DiagnosticOptions &opts) { - DiagnosticOptions *m_options = new DiagnosticOptions(opts); - m_options->ShowPresumedLoc = true; - m_options->ShowLevel = false; - m_os.reset(new llvm::raw_string_ostream(m_output)); - m_passthrough.reset( - new clang::TextDiagnosticPrinter(*m_os, m_options, false)); + DiagnosticOptions *options = new DiagnosticOptions(opts); + options->ShowPresumedLoc = true; + options->ShowLevel = false; + m_os = std::make_shared<llvm::raw_string_ostream>(m_output); + m_passthrough = + std::make_shared<clang::TextDiagnosticPrinter>(*m_os, options); } void ResetManager(DiagnosticManager *manager = nullptr) { m_manager = manager; } + /// Returns the last ClangDiagnostic message that the DiagnosticManager + /// received or a nullptr if the DiagnosticMangager hasn't seen any + /// Clang diagnostics yet. + ClangDiagnostic *MaybeGetLastClangDiag() const { + if (m_manager->Diagnostics().empty()) + return nullptr; + lldb_private::Diagnostic *diag = m_manager->Diagnostics().back().get(); + ClangDiagnostic *clang_diag = dyn_cast<ClangDiagnostic>(diag); + return clang_diag; + } + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) override { if (!m_manager) { @@ -180,6 +200,9 @@ public: return; } + // Update error/warning counters. + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); + // Render diagnostic message to m_output. m_output.clear(); m_passthrough->HandleDiagnostic(DiagLevel, Info); @@ -203,11 +226,29 @@ public: case DiagnosticsEngine::Level::Note: m_manager->AppendMessageToDiagnostic(m_output); make_new_diagnostic = false; + + // 'note:' diagnostics for errors and warnings can also contain Fix-Its. + // We add these Fix-Its to the last error diagnostic to make sure + // that we later have all Fix-Its related to an 'error' diagnostic when + // we apply them to the user expression. + auto *clang_diag = MaybeGetLastClangDiag(); + // If we don't have a previous diagnostic there is nothing to do. + // If the previous diagnostic already has its own Fix-Its, assume that + // the 'note:' Fix-It is just an alternative way to solve the issue and + // ignore these Fix-Its. + if (!clang_diag || clang_diag->HasFixIts()) + break; + // Ignore all Fix-Its that are not associated with an error. + if (clang_diag->GetSeverity() != eDiagnosticSeverityError) + break; + AddAllFixIts(clang_diag, Info); + break; } if (make_new_diagnostic) { // ClangDiagnostic messages are expected to have no whitespace/newlines // around them. - std::string stripped_output = llvm::StringRef(m_output).trim(); + std::string stripped_output = + std::string(llvm::StringRef(m_output).trim()); auto new_diagnostic = std::make_unique<ClangDiagnostic>( stripped_output, severity, Info.getID()); @@ -216,20 +257,18 @@ public: // enough context in an expression for the warning to be useful. // FIXME: Should we try to filter out FixIts that apply to our generated // code, and not the user's expression? - if (severity == eDiagnosticSeverityError) { - size_t num_fixit_hints = Info.getNumFixItHints(); - for (size_t i = 0; i < num_fixit_hints; i++) { - const clang::FixItHint &fixit = Info.getFixItHint(i); - if (!fixit.isNull()) - new_diagnostic->AddFixitHint(fixit); - } - } + if (severity == eDiagnosticSeverityError) + AddAllFixIts(new_diagnostic.get(), Info); m_manager->AddDiagnostic(std::move(new_diagnostic)); } } - clang::TextDiagnosticPrinter *GetPassthrough() { return m_passthrough.get(); } + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override { + m_passthrough->BeginSourceFile(LO, PP); + } + + void EndSourceFile() override { m_passthrough->EndSourceFile(); } private: DiagnosticManager *m_manager = nullptr; @@ -253,9 +292,9 @@ static void SetupModuleHeaderPaths(CompilerInstance *compiler, } llvm::SmallString<128> module_cache; - auto props = ModuleList::GetGlobalModuleListProperties(); + const auto &props = ModuleList::GetGlobalModuleListProperties(); props.GetClangModulesCachePath().GetPath(module_cache); - search_opts.ModuleCachePath = module_cache.str(); + search_opts.ModuleCachePath = std::string(module_cache.str()); LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str()); search_opts.ResourceDir = GetClangResourceDir().GetPath(); @@ -279,28 +318,27 @@ ClangExpressionParser::ClangExpressionParser( // We can't compile expressions without a target. So if the exe_scope is // null or doesn't have a target, then we just need to get out of here. I'll - // lldb_assert and not make any of the compiler objects since + // lldbassert and not make any of the compiler objects since // I can't return errors directly from the constructor. Further calls will // check if the compiler was made and // bag out if it wasn't. if (!exe_scope) { - lldb_assert(exe_scope, "Can't make an expression parser with a null scope.", - __FUNCTION__, __FILE__, __LINE__); + lldbassert(exe_scope && + "Can't make an expression parser with a null scope."); return; } lldb::TargetSP target_sp; target_sp = exe_scope->CalculateTarget(); if (!target_sp) { - lldb_assert(target_sp.get(), - "Can't make an expression parser with a null target.", - __FUNCTION__, __FILE__, __LINE__); + lldbassert(target_sp.get() && + "Can't make an expression parser with a null target."); return; } // 1. Create a new compiler instance. - m_compiler.reset(new CompilerInstance()); + m_compiler = std::make_unique<CompilerInstance>(); // When capturing a reproducer, hook up the file collector with clang to // collector modules and headers. @@ -391,9 +429,13 @@ ClangExpressionParser::ClangExpressionParser( // target. In this case, a specialized language runtime is available and we // can query it for extra options. For 99% of use cases, this will not be // needed and should be provided when basic platform detection is not enough. - if (lang_rt) + // FIXME: Generalize this. Only RenderScriptRuntime currently supports this + // currently. Hardcoding this isn't ideal but it's better than LanguageRuntime + // having knowledge of clang::TargetOpts. + if (auto *renderscript_rt = + llvm::dyn_cast_or_null<RenderScriptRuntime>(lang_rt)) overridden_target_opts = - lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); + renderscript_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); if (overridden_target_opts) if (log && log->GetVerbose()) { @@ -606,11 +648,12 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->createASTContext(); clang::ASTContext &ast_context = m_compiler->getASTContext(); - m_ast_context.reset(new ClangASTContext(ast_context)); + m_ast_context = std::make_unique<TypeSystemClang>( + "Expression ASTContext for '" + m_filename + "'", ast_context); std::string module_name("$__lldb_module"); - m_llvm_context.reset(new LLVMContext()); + m_llvm_context = std::make_unique<LLVMContext>(); m_code_generator.reset(CreateLLVMCodeGen( m_compiler->getDiagnostics(), module_name, m_compiler->getHeaderSearchOpts(), m_compiler->getPreprocessorOpts(), @@ -631,11 +674,33 @@ class CodeComplete : public CodeCompleteConsumer { std::string m_expr; unsigned m_position = 0; - CompletionRequest &m_request; /// The printing policy we use when printing declarations for our completion /// descriptions. clang::PrintingPolicy m_desc_policy; + struct CompletionWithPriority { + CompletionResult::Completion completion; + /// See CodeCompletionResult::Priority; + unsigned Priority; + + /// Establishes a deterministic order in a list of CompletionWithPriority. + /// The order returned here is the order in which the completions are + /// displayed to the user. + bool operator<(const CompletionWithPriority &o) const { + // High priority results should come first. + if (Priority != o.Priority) + return Priority > o.Priority; + + // Identical priority, so just make sure it's a deterministic order. + return completion.GetUniqueKey() < o.completion.GetUniqueKey(); + } + }; + + /// The stored completions. + /// Warning: These are in a non-deterministic order until they are sorted + /// and returned back to the caller. + std::vector<CompletionWithPriority> m_completions; + /// Returns true if the given character can be used in an identifier. /// This also returns true for numbers because for completion we usually /// just iterate backwards over iterators. @@ -652,7 +717,7 @@ class CodeComplete : public CodeCompleteConsumer { /// Drops all tokens in front of the expression that are unrelated for /// the completion of the cmd line. 'unrelated' means here that the token /// is not interested for the lldb completion API result. - StringRef dropUnrelatedFrontTokens(StringRef cmd) { + StringRef dropUnrelatedFrontTokens(StringRef cmd) const { if (cmd.empty()) return cmd; @@ -673,18 +738,18 @@ class CodeComplete : public CodeCompleteConsumer { } /// Removes the last identifier token from the given cmd line. - StringRef removeLastToken(StringRef cmd) { + StringRef removeLastToken(StringRef cmd) const { while (!cmd.empty() && IsIdChar(cmd.back())) { cmd = cmd.drop_back(); } return cmd; } - /// Attemps to merge the given completion from the given position into the + /// Attempts to merge the given completion from the given position into the /// existing command. Returns the completion string that can be returned to /// the lldb completion API. std::string mergeCompletion(StringRef existing, unsigned pos, - StringRef completion) { + StringRef completion) const { StringRef existing_command = existing.substr(0, pos); // We rewrite the last token with the completion, so let's drop that // token from the command. @@ -706,11 +771,10 @@ public: /// \param[out] position /// The character position of the user cursor in the `expr` parameter. /// - CodeComplete(CompletionRequest &request, clang::LangOptions ops, - std::string expr, unsigned position) + CodeComplete(clang::LangOptions ops, std::string expr, unsigned position) : CodeCompleteConsumer(CodeCompleteOptions()), m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr), - m_position(position), m_request(request), m_desc_policy(ops) { + m_position(position), m_desc_policy(ops) { // Ensure that the printing policy is producing a description that is as // short as possible. @@ -723,9 +787,6 @@ public: m_desc_policy.Bool = true; } - /// Deregisters and destroys this code-completion consumer. - ~CodeComplete() override {} - /// \name Code-completion filtering /// Check if the result should be filtered out. bool isResultFilteredOut(StringRef Filter, @@ -753,6 +814,85 @@ public: return true; } +private: + /// Generate the completion strings for the given CodeCompletionResult. + /// Note that this function has to process results that could come in + /// non-deterministic order, so this function should have no side effects. + /// To make this easier to enforce, this function and all its parameters + /// should always be const-qualified. + /// \return Returns llvm::None if no completion should be provided for the + /// given CodeCompletionResult. + llvm::Optional<CompletionWithPriority> + getCompletionForResult(const CodeCompletionResult &R) const { + std::string ToInsert; + std::string Description; + // Handle the different completion kinds that come from the Sema. + switch (R.Kind) { + case CodeCompletionResult::RK_Declaration: { + const NamedDecl *D = R.Declaration; + ToInsert = R.Declaration->getNameAsString(); + // If we have a function decl that has no arguments we want to + // complete the empty parantheses for the user. If the function has + // arguments, we at least complete the opening bracket. + if (const FunctionDecl *F = dyn_cast<FunctionDecl>(D)) { + if (F->getNumParams() == 0) + ToInsert += "()"; + else + ToInsert += "("; + raw_string_ostream OS(Description); + F->print(OS, m_desc_policy, false); + OS.flush(); + } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { + Description = V->getType().getAsString(m_desc_policy); + } else if (const FieldDecl *F = dyn_cast<FieldDecl>(D)) { + Description = F->getType().getAsString(m_desc_policy); + } else if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) { + // If we try to complete a namespace, then we can directly append + // the '::'. + if (!N->isAnonymousNamespace()) + ToInsert += "::"; + } + break; + } + case CodeCompletionResult::RK_Keyword: + ToInsert = R.Keyword; + break; + case CodeCompletionResult::RK_Macro: + ToInsert = R.Macro->getName().str(); + break; + case CodeCompletionResult::RK_Pattern: + ToInsert = R.Pattern->getTypedText(); + break; + } + // We also filter some internal lldb identifiers here. The user + // shouldn't see these. + if (llvm::StringRef(ToInsert).startswith("$__lldb_")) + return llvm::None; + if (ToInsert.empty()) + return llvm::None; + // Merge the suggested Token into the existing command line to comply + // with the kind of result the lldb API expects. + std::string CompletionSuggestion = + mergeCompletion(m_expr, m_position, ToInsert); + + CompletionResult::Completion completion(CompletionSuggestion, Description, + CompletionMode::Normal); + return {{completion, R.Priority}}; + } + +public: + /// Adds the completions to the given CompletionRequest. + void GetCompletions(CompletionRequest &request) { + // Bring m_completions into a deterministic order and pass it on to the + // CompletionRequest. + llvm::sort(m_completions); + + for (const CompletionWithPriority &C : m_completions) + request.AddCompletion(C.completion.GetCompletion(), + C.completion.GetDescription(), + C.completion.GetMode()); + } + /// \name Code-completion callbacks /// Process the finalized code-completion results. void ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, @@ -771,59 +911,11 @@ public: continue; CodeCompletionResult &R = Results[I]; - std::string ToInsert; - std::string Description; - // Handle the different completion kinds that come from the Sema. - switch (R.Kind) { - case CodeCompletionResult::RK_Declaration: { - const NamedDecl *D = R.Declaration; - ToInsert = R.Declaration->getNameAsString(); - // If we have a function decl that has no arguments we want to - // complete the empty parantheses for the user. If the function has - // arguments, we at least complete the opening bracket. - if (const FunctionDecl *F = dyn_cast<FunctionDecl>(D)) { - if (F->getNumParams() == 0) - ToInsert += "()"; - else - ToInsert += "("; - raw_string_ostream OS(Description); - F->print(OS, m_desc_policy, false); - OS.flush(); - } else if (const VarDecl *V = dyn_cast<VarDecl>(D)) { - Description = V->getType().getAsString(m_desc_policy); - } else if (const FieldDecl *F = dyn_cast<FieldDecl>(D)) { - Description = F->getType().getAsString(m_desc_policy); - } else if (const NamespaceDecl *N = dyn_cast<NamespaceDecl>(D)) { - // If we try to complete a namespace, then we can directly append - // the '::'. - if (!N->isAnonymousNamespace()) - ToInsert += "::"; - } - break; - } - case CodeCompletionResult::RK_Keyword: - ToInsert = R.Keyword; - break; - case CodeCompletionResult::RK_Macro: - ToInsert = R.Macro->getName().str(); - break; - case CodeCompletionResult::RK_Pattern: - ToInsert = R.Pattern->getTypedText(); - break; - } - // At this point all information is in the ToInsert string. - - // We also filter some internal lldb identifiers here. The user - // shouldn't see these. - if (StringRef(ToInsert).startswith("$__lldb_")) + llvm::Optional<CompletionWithPriority> CompletionAndPriority = + getCompletionForResult(R); + if (!CompletionAndPriority) continue; - if (!ToInsert.empty()) { - // Merge the suggested Token into the existing command line to comply - // with the kind of result the lldb API expects. - std::string CompletionSuggestion = - mergeCompletion(m_expr, m_position, ToInsert); - m_request.AddCompletion(CompletionSuggestion, Description); - } + m_completions.push_back(*CompletionAndPriority); } } @@ -860,12 +952,13 @@ bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line, // the LLVMUserExpression which exposes the right API. This should never fail // as we always have a ClangUserExpression whenever we call this. ClangUserExpression *llvm_expr = cast<ClangUserExpression>(&m_expr); - CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr->GetUserText(), + CodeComplete CC(m_compiler->getLangOpts(), llvm_expr->GetUserText(), typed_pos); // We don't need a code generator for parsing. m_code_generator.reset(); // Start parsing the expression with our custom code completion consumer. ParseInternal(mgr, &CC, line, pos); + CC.GetCompletions(request); return true; } @@ -881,7 +974,6 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangDiagnosticManagerAdapter *adapter = static_cast<ClangDiagnosticManagerAdapter *>( m_compiler->getDiagnostics().getClient()); - auto diag_buf = adapter->GetPassthrough(); adapter->ResetManager(&diagnostic_manager); @@ -936,8 +1028,8 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer))); } - diag_buf->BeginSourceFile(m_compiler->getLangOpts(), - &m_compiler->getPreprocessor()); + adapter->BeginSourceFile(m_compiler->getLangOpts(), + &m_compiler->getPreprocessor()); ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -961,11 +1053,11 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, std::unique_ptr<clang::ASTConsumer> Consumer; if (ast_transformer) { - Consumer.reset(new ASTConsumerForwarder(ast_transformer)); + Consumer = std::make_unique<ASTConsumerForwarder>(ast_transformer); } else if (m_code_generator) { - Consumer.reset(new ASTConsumerForwarder(m_code_generator.get())); + Consumer = std::make_unique<ASTConsumerForwarder>(m_code_generator.get()); } else { - Consumer.reset(new ASTConsumer()); + Consumer = std::make_unique<ASTConsumer>(); } clang::ASTContext &ast_context = m_compiler->getASTContext(); @@ -1022,9 +1114,9 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, // original behavior of ParseAST (which also destroys the Sema after parsing). m_compiler->setSema(nullptr); - diag_buf->EndSourceFile(); + adapter->EndSourceFile(); - unsigned num_errors = diag_buf->getNumErrors(); + unsigned num_errors = adapter->getNumErrors(); if (m_pp_callbacks && m_pp_callbacks->hasErrors()) { num_errors++; @@ -1065,6 +1157,28 @@ ClangExpressionParser::GetClangTargetABI(const ArchSpec &target_arch) { return abi; } +/// Applies the given Fix-It hint to the given commit. +static void ApplyFixIt(const FixItHint &fixit, clang::edit::Commit &commit) { + // This is cobbed from clang::Rewrite::FixItRewriter. + if (fixit.CodeToInsert.empty()) { + if (fixit.InsertFromRange.isValid()) { + commit.insertFromRange(fixit.RemoveRange.getBegin(), + fixit.InsertFromRange, /*afterToken=*/false, + fixit.BeforePreviousInsertions); + return; + } + commit.remove(fixit.RemoveRange); + return; + } + if (fixit.RemoveRange.isTokenRange() || + fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) { + commit.replace(fixit.RemoveRange, fixit.CodeToInsert); + return; + } + commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, + /*afterToken=*/false, fixit.BeforePreviousInsertions); +} + bool ClangExpressionParser::RewriteExpression( DiagnosticManager &diagnostic_manager) { clang::SourceManager &source_manager = m_compiler->getSourceManager(); @@ -1096,26 +1210,12 @@ bool ClangExpressionParser::RewriteExpression( for (const auto &diag : diagnostic_manager.Diagnostics()) { const auto *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag.get()); - if (diagnostic && diagnostic->HasFixIts()) { - for (const FixItHint &fixit : diagnostic->FixIts()) { - // This is cobbed from clang::Rewrite::FixItRewriter. - if (fixit.CodeToInsert.empty()) { - if (fixit.InsertFromRange.isValid()) { - commit.insertFromRange(fixit.RemoveRange.getBegin(), - fixit.InsertFromRange, /*afterToken=*/false, - fixit.BeforePreviousInsertions); - } else - commit.remove(fixit.RemoveRange); - } else { - if (fixit.RemoveRange.isTokenRange() || - fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) - commit.replace(fixit.RemoveRange, fixit.CodeToInsert); - else - commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, - /*afterToken=*/false, fixit.BeforePreviousInsertions); - } - } - } + if (!diagnostic) + continue; + if (!diagnostic->HasFixIts()) + continue; + for (const FixItHint &fixit : diagnostic->FixIts()) + ApplyFixIt(fixit, commit); } // FIXME - do we want to try to propagate specific errors here? @@ -1230,18 +1330,13 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( type_system_helper->DeclMap(); // result can be NULL if (decl_map) { - Target *target = exe_ctx.GetTargetPtr(); - auto &error_stream = target->GetDebugger().GetErrorStream(); + StreamString error_stream; IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), *execution_unit_sp, error_stream, function_name.AsCString()); - bool ir_can_run = - ir_for_target.runOnModule(*execution_unit_sp->GetModule()); - - if (!ir_can_run) { - err.SetErrorString( - "The expression could not be prepared to run in the target"); + if (!ir_for_target.runOnModule(*execution_unit_sp->GetModule())) { + err.SetErrorString(error_stream.GetString()); return err; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 4a410cecb94a..6afee22da8d1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionParser_h_ -#define liblldb_ClangExpressionParser_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/ExpressionParser.h" #include "lldb/Utility/ArchSpec.h" @@ -19,13 +18,20 @@ #include <string> #include <vector> +namespace llvm { +class LLVMContext; +} + namespace clang { +class CodeGenerator; class CodeCompleteConsumer; -} +class CompilerInstance; +} // namespace clang namespace lldb_private { class IRExecutionUnit; +class TypeSystemClang; /// \class ClangExpressionParser ClangExpressionParser.h /// "lldb/Expression/ClangExpressionParser.h" Encapsulates an instance of @@ -171,7 +177,7 @@ private: class LLDBPreprocessorCallbacks; LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor ///encounters module imports - std::unique_ptr<ClangASTContext> m_ast_context; + std::unique_ptr<TypeSystemClang> m_ast_context; std::vector<std::string> m_include_directories; /// File name used for the user expression. @@ -179,4 +185,4 @@ private: }; } -#endif // liblldb_ClangExpressionParser_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONPARSER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index 7ebb5fee1ec6..a429963277d1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionSourceCode.cpp ---------------------------*- C++ -*-===// +//===-- ClangExpressionSourceCode.cpp -------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,6 +9,7 @@ #include "ClangExpressionSourceCode.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringRef.h" @@ -173,8 +174,8 @@ static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode( llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix, - llvm::StringRef body, Wrapping wrap) - : ExpressionSourceCode(name, prefix, body, wrap) { + llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind) + : ExpressionSourceCode(name, prefix, body, wrap), m_wrap_kind(wrap_kind) { // Use #line markers to pretend that we have a single-line source file // containing only the user expression. This will hide our wrapper code // from the user when we render diagnostics with Clang. @@ -260,10 +261,9 @@ TokenVerifier::TokenVerifier(std::string body) { } } -static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, - StreamString &stream, - const std::string &expr, - lldb::LanguageType wrapping_language) { +void ClangExpressionSourceCode::AddLocalVariableDecls( + const lldb::VariableListSP &var_list_sp, StreamString &stream, + const std::string &expr) const { TokenVerifier tokens(expr); for (size_t i = 0; i < var_list_sp->GetSize(); i++) { @@ -280,13 +280,12 @@ static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, if (!expr.empty() && !tokens.hasToken(var_name.GetStringRef())) continue; - if ((var_name == "self" || var_name == "_cmd") && - (wrapping_language == lldb::eLanguageTypeObjC || - wrapping_language == lldb::eLanguageTypeObjC_plus_plus)) + const bool is_objc = m_wrap_kind == WrapKind::ObjCInstanceMethod || + m_wrap_kind == WrapKind::ObjCStaticMethod; + if ((var_name == "self" || var_name == "_cmd") && is_objc) continue; - if (var_name == "this" && - wrapping_language == lldb::eLanguageTypeC_plus_plus) + if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) continue; stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); @@ -294,9 +293,8 @@ static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, } bool ClangExpressionSourceCode::GetText( - std::string &text, lldb::LanguageType wrapping_language, bool static_method, - ExecutionContext &exe_ctx, bool add_locals, bool force_add_all_locals, - llvm::ArrayRef<std::string> modules) const { + std::string &text, ExecutionContext &exe_ctx, bool add_locals, + bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; std::string module_macros; @@ -373,21 +371,11 @@ bool ClangExpressionSourceCode::GetText( lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true); AddLocalVariableDecls(var_list_sp, lldb_local_var_decls, - force_add_all_locals ? "" : m_body, - wrapping_language); + force_add_all_locals ? "" : m_body); } } if (m_wrap) { - switch (wrapping_language) { - default: - return false; - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeObjC: - break; - } - // Generate a list of @import statements that will import the specified // module into our expression. std::string module_imports; @@ -406,22 +394,12 @@ bool ClangExpressionSourceCode::GetText( // First construct a tagged form of the user expression so we can find it // later: std::string tagged_body; - switch (wrapping_language) { - default: - tagged_body = m_body; - break; - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeObjC: - tagged_body.append(m_start_marker); - tagged_body.append(m_body); - tagged_body.append(m_end_marker); - break; - } - switch (wrapping_language) { - default: - break; - case lldb::eLanguageTypeC: + tagged_body.append(m_start_marker); + tagged_body.append(m_body); + tagged_body.append(m_end_marker); + + switch (m_wrap_kind) { + case WrapKind::Function: wrap_stream.Printf("%s" "void \n" "%s(void *$__lldb_arg) \n" @@ -432,7 +410,7 @@ bool ClangExpressionSourceCode::GetText( module_imports.c_str(), m_name.c_str(), lldb_local_var_decls.GetData(), tagged_body.c_str()); break; - case lldb::eLanguageTypeC_plus_plus: + case WrapKind::CppMemberFunction: wrap_stream.Printf("%s" "void \n" "$__lldb_class::%s(void *$__lldb_arg) \n" @@ -443,42 +421,42 @@ bool ClangExpressionSourceCode::GetText( module_imports.c_str(), m_name.c_str(), lldb_local_var_decls.GetData(), tagged_body.c_str()); break; - case lldb::eLanguageTypeObjC: - if (static_method) { - wrap_stream.Printf( - "%s" - "@interface $__lldb_objc_class ($__lldb_category) \n" - "+(void)%s:(void *)$__lldb_arg; \n" - "@end \n" - "@implementation $__lldb_objc_class ($__lldb_category) \n" - "+(void)%s:(void *)$__lldb_arg \n" - "{ \n" - " %s; \n" - "%s" - "} \n" - "@end \n", - module_imports.c_str(), m_name.c_str(), m_name.c_str(), - lldb_local_var_decls.GetData(), tagged_body.c_str()); - } else { - wrap_stream.Printf( - "%s" - "@interface $__lldb_objc_class ($__lldb_category) \n" - "-(void)%s:(void *)$__lldb_arg; \n" - "@end \n" - "@implementation $__lldb_objc_class ($__lldb_category) \n" - "-(void)%s:(void *)$__lldb_arg \n" - "{ \n" - " %s; \n" - "%s" - "} \n" - "@end \n", - module_imports.c_str(), m_name.c_str(), m_name.c_str(), - lldb_local_var_decls.GetData(), tagged_body.c_str()); - } + case WrapKind::ObjCInstanceMethod: + wrap_stream.Printf( + "%s" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "-(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "%s" + "} \n" + "@end \n", + module_imports.c_str(), m_name.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); + break; + + case WrapKind::ObjCStaticMethod: + wrap_stream.Printf( + "%s" + "@interface $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg; \n" + "@end \n" + "@implementation $__lldb_objc_class ($__lldb_category) \n" + "+(void)%s:(void *)$__lldb_arg \n" + "{ \n" + " %s; \n" + "%s" + "} \n" + "@end \n", + module_imports.c_str(), m_name.c_str(), m_name.c_str(), + lldb_local_var_decls.GetData(), tagged_body.c_str()); break; } - text = wrap_stream.GetString(); + text = std::string(wrap_stream.GetString()); } else { text.append(m_body); } @@ -487,17 +465,7 @@ bool ClangExpressionSourceCode::GetText( } bool ClangExpressionSourceCode::GetOriginalBodyBounds( - std::string transformed_text, lldb::LanguageType wrapping_language, - size_t &start_loc, size_t &end_loc) { - switch (wrapping_language) { - default: - return false; - case lldb::eLanguageTypeC: - case lldb::eLanguageTypeC_plus_plus: - case lldb::eLanguageTypeObjC: - break; - } - + std::string transformed_text, size_t &start_loc, size_t &end_loc) { start_loc = transformed_text.find(m_start_marker); if (start_loc == std::string::npos) return false; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h index 1d159670b962..9a54f0e3ad8d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionSourceCode_h -#define liblldb_ClangExpressionSourceCode_h +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONSOURCECODE_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONSOURCECODE_H #include "lldb/Expression/Expression.h" #include "lldb/Expression/ExpressionSourceCode.h" @@ -28,20 +28,30 @@ public: static const llvm::StringRef g_prefix_file_name; static const char *g_expression_prefix; + /// The possible ways an expression can be wrapped. + enum class WrapKind { + /// Wrapped in a non-static member function of a C++ class. + CppMemberFunction, + /// Wrapped in an instance Objective-C method. + ObjCInstanceMethod, + /// Wrapped in a static Objective-C method. + ObjCStaticMethod, + /// Wrapped in a non-member function. + /// Note that this is also used for static member functions of a C++ class. + Function + }; + static ClangExpressionSourceCode *CreateWrapped(llvm::StringRef filename, llvm::StringRef prefix, - llvm::StringRef body) { + llvm::StringRef body, + WrapKind wrap_kind) { return new ClangExpressionSourceCode(filename, "$__lldb_expr", prefix, body, - Wrap); + Wrap, wrap_kind); } /// Generates the source code that will evaluate the expression. /// /// \param text output parameter containing the source code string. - /// \param wrapping_language If the expression is supossed to be wrapped, - /// then this is the language that should be used for that. - /// \param static_method True iff the expression is valuated inside a static - /// Objective-C method. /// \param exe_ctx The execution context in which the expression will be /// evaluated. /// \param add_locals True iff local variables should be injected into the @@ -51,8 +61,7 @@ public: /// \param modules A list of (C++) modules that the expression should import. /// /// \return true iff the source code was successfully generated. - bool GetText(std::string &text, lldb::LanguageType wrapping_language, - bool static_method, ExecutionContext &exe_ctx, bool add_locals, + bool GetText(std::string &text, ExecutionContext &exe_ctx, bool add_locals, bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const; @@ -60,19 +69,24 @@ public: // passed to CreateWrapped. Return true if the bounds could be found. This // will also work on text with FixItHints applied. bool GetOriginalBodyBounds(std::string transformed_text, - lldb::LanguageType wrapping_language, size_t &start_loc, size_t &end_loc); protected: ClangExpressionSourceCode(llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix, llvm::StringRef body, - Wrapping wrap); + Wrapping wrap, WrapKind wrap_kind); private: + void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, + StreamString &stream, + const std::string &expr) const; + /// String marking the start of the user expression. std::string m_start_marker; /// String marking the end of the user expression. std::string m_end_marker; + /// How the expression has been wrapped. + const WrapKind m_wrap_kind; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp index b5a2c80b5349..9af92e194da9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp @@ -1,4 +1,4 @@ -//===-- ClangExpressionVariable.cpp -----------------------------*- C++ -*-===// +//===-- ClangExpressionVariable.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 0e6de28ee4df..58d589962abe 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangExpressionVariable_h_ -#define liblldb_ClangExpressionVariable_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H #include <signal.h> #include <stdint.h> @@ -19,7 +19,6 @@ #include "llvm/Support/Casting.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/TaggedASTType.h" @@ -30,6 +29,10 @@ namespace llvm { class Value; } +namespace clang { +class NamedDecl; +} + namespace lldb_private { class ValueObjectConstResult; @@ -114,11 +117,9 @@ public: class ParserVars { public: ParserVars() - : m_parser_type(), m_named_decl(nullptr), m_llvm_value(nullptr), + : m_named_decl(nullptr), m_llvm_value(nullptr), m_lldb_value(), m_lldb_var(), m_lldb_sym(nullptr) {} - TypeFromParser - m_parser_type; ///< The type of the variable according to the parser const clang::NamedDecl *m_named_decl; ///< The Decl corresponding to this variable llvm::Value *m_llvm_value; ///< The IR value corresponding to this variable; @@ -196,9 +197,11 @@ public: } /// Members - DISALLOW_COPY_AND_ASSIGN(ClangExpressionVariable); + ClangExpressionVariable(const ClangExpressionVariable &) = delete; + const ClangExpressionVariable & + operator=(const ClangExpressionVariable &) = delete; }; } // namespace lldb_private -#endif // liblldb_ClangExpressionVariable_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp new file mode 100644 index 000000000000..390afb458b5a --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -0,0 +1,88 @@ +//===-- ClangExternalASTSourceCallbacks.cpp -------------------------------===// +// +// 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 "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" + +using namespace lldb_private; + +char ClangExternalASTSourceCallbacks::ID; + +void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) { + m_ast.CompleteTagDecl(tag_decl); +} + +void ClangExternalASTSourceCallbacks::CompleteType( + clang::ObjCInterfaceDecl *objc_decl) { + m_ast.CompleteObjCInterfaceDecl(objc_decl); +} + +bool ClangExternalASTSourceCallbacks::layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) { + return m_ast.LayoutRecordType(Record, Size, Alignment, FieldOffsets, + BaseOffsets, VirtualBaseOffsets); +} + +void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls( + const clang::DeclContext *decl_ctx, + llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, + llvm::SmallVectorImpl<clang::Decl *> &decls) { + if (decl_ctx) { + clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>( + const_cast<clang::DeclContext *>(decl_ctx)); + if (tag_decl) + CompleteType(tag_decl); + } +} + +bool ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName( + const clang::DeclContext *DC, clang::DeclarationName Name) { + llvm::SmallVector<clang::NamedDecl *, 4> decls; + // Objective-C methods are not added into the LookupPtr when they originate + // from an external source. SetExternalVisibleDeclsForName() adds them. + if (auto *oid = llvm::dyn_cast<clang::ObjCInterfaceDecl>(DC)) { + clang::ObjCContainerDecl::method_range noload_methods(oid->noload_decls()); + for (auto *omd : noload_methods) + if (omd->getDeclName() == Name) + decls.push_back(omd); + } + return !SetExternalVisibleDeclsForName(DC, Name, decls).empty(); +} + +OptionalClangModuleID +ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) { + m_modules.push_back(module); + unsigned id = m_modules.size(); + m_ids.insert({module, id}); + return OptionalClangModuleID(id); +} + +llvm::Optional<clang::ASTSourceDescriptor> +ClangExternalASTSourceCallbacks::getSourceDescriptor(unsigned id) { + if (clang::Module *module = getModule(id)) + return {*module}; + return {}; +} + +clang::Module *ClangExternalASTSourceCallbacks::getModule(unsigned id) { + if (id && id <= m_modules.size()) + return m_modules[id - 1]; + return nullptr; +} + +OptionalClangModuleID +ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) { + return OptionalClangModuleID(m_ids[module]); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h new file mode 100644 index 000000000000..69088d9c82a5 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -0,0 +1,66 @@ +//===-- ClangExternalASTSourceCallbacks.h -----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H + +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "clang/Basic/Module.h" + +namespace lldb_private { + +class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { + /// LLVM RTTI support. + static char ID; + +public: + /// LLVM RTTI support. + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); } + + ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {} + + void FindExternalLexicalDecls( + const clang::DeclContext *DC, + llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant, + llvm::SmallVectorImpl<clang::Decl *> &Result) override; + + bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC, + clang::DeclarationName Name) override; + + void CompleteType(clang::TagDecl *tag_decl) override; + + void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override; + + bool layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) override; + + TypeSystemClang &GetTypeSystem() const { return m_ast; } + + /// Module-related methods. + /// \{ + llvm::Optional<clang::ASTSourceDescriptor> + getSourceDescriptor(unsigned ID) override; + clang::Module *getModule(unsigned ID) override; + OptionalClangModuleID RegisterModule(clang::Module *module); + OptionalClangModuleID GetIDForModule(clang::Module *module); + /// \} +private: + TypeSystemClang &m_ast; + std::vector<clang::Module *> m_modules; + llvm::DenseMap<clang::Module *, unsigned> m_ids; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 7f7c0a97f538..0c9ad2021035 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -1,4 +1,4 @@ -//===-- ClangFunctionCaller.cpp ---------------------------------*- C++ -*-===// +//===-- ClangFunctionCaller.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -21,12 +21,12 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/IR/Module.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" @@ -209,8 +209,8 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, clang::ASTConsumer * ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer( clang::ASTConsumer *passthrough) { - m_struct_extractor.reset(new ASTStructExtractor( - passthrough, m_owner.GetWrapperStructName(), m_owner)); + m_struct_extractor = std::make_unique<ASTStructExtractor>( + passthrough, m_owner.GetWrapperStructName(), m_owner); return m_struct_extractor.get(); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h index 150a913152d0..8060b8c0aedc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h @@ -6,13 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangFunctionCaller_h_ -#define liblldb_ClangFunctionCaller_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H #include "ClangExpressionHelper.h" #include "lldb/Core/Address.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/FunctionCaller.h" @@ -150,4 +149,4 @@ private: } // namespace lldb_private -#endif // liblldb_ClangFunctionCaller_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGFUNCTIONCALLER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 42d3f22014dd..8abb7e420575 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -1,4 +1,4 @@ -//===-- ClangHost.cpp -------------------------------------------*- C++ -*-===// +//===-- ClangHost.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -67,10 +67,10 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, llvm::sys::path::native(relative_path); llvm::sys::path::append(clang_dir, relative_path); if (!verify || VerifyClangPath(clang_dir)) { - LLDB_LOGF(log, - "DefaultComputeClangResourceDir: Setting ClangResourceDir " - "to \"%s\", verify = %s", - clang_dir.str().str().c_str(), verify ? "true" : "false"); + LLDB_LOG(log, + "DefaultComputeClangResourceDir: Setting ClangResourceDir " + "to \"{0}\", verify = {1}", + clang_dir.str(), verify ? "true" : "false"); file_spec.GetDirectory().SetString(clang_dir); FileSystem::Instance().Resolve(file_spec); return true; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h index 9d49188178cd..d6809909a625 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H -#define LLDB_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGHOST_H namespace lldb_private { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 0696c669f2e2..95acb883774d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -1,4 +1,4 @@ -//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===// +//===-- ClangModulesDeclVendor.cpp ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,11 +6,10 @@ // //===----------------------------------------------------------------------===// -#include <mutex> - #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Parse/Parser.h" @@ -24,10 +23,10 @@ #include "ClangModulesDeclVendor.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Target.h" @@ -37,6 +36,9 @@ #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" +#include <memory> +#include <mutex> + using namespace lldb_private; namespace { @@ -54,10 +56,21 @@ public: void DumpDiagnostics(Stream &error_stream); + void BeginSourceFile(const clang::LangOptions &LangOpts, + const clang::Preprocessor *PP = nullptr) override; + void EndSourceFile() override; + private: typedef std::pair<clang::DiagnosticsEngine::Level, std::string> IDAndDiagnostic; std::vector<IDAndDiagnostic> m_diagnostics; + /// The DiagnosticPrinter used for creating the full diagnostic messages + /// that are stored in m_diagnostics. + std::shared_ptr<clang::TextDiagnosticPrinter> m_diag_printer; + /// Output stream of m_diag_printer. + std::shared_ptr<llvm::raw_string_ostream> m_os; + /// Output string filled by m_os. Will be reused for different diagnostics. + std::string m_output; Log *m_log; }; @@ -108,25 +121,30 @@ private: typedef std::set<ModuleID> ImportedModuleSet; ImportedModuleMap m_imported_modules; ImportedModuleSet m_user_imported_modules; - // We assume that every ASTContext has an ClangASTContext, so we also store - // a custom ClangASTContext for our internal ASTContext. - std::unique_ptr<ClangASTContext> m_ast_context; + // We assume that every ASTContext has an TypeSystemClang, so we also store + // a custom TypeSystemClang for our internal ASTContext. + std::unique_ptr<TypeSystemClang> m_ast_context; }; } // anonymous namespace StoringDiagnosticConsumer::StoringDiagnosticConsumer() { m_log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + clang::DiagnosticOptions *m_options = new clang::DiagnosticOptions(); + m_os = std::make_shared<llvm::raw_string_ostream>(m_output); + m_diag_printer = + std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options); } void StoringDiagnosticConsumer::HandleDiagnostic( clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) { - llvm::SmallVector<char, 256> diagnostic_string; + // Print the diagnostic to m_output. + m_output.clear(); + m_diag_printer->HandleDiagnostic(DiagLevel, info); + m_os->flush(); - info.FormatDiagnostic(diagnostic_string); - - m_diagnostics.push_back( - IDAndDiagnostic(DiagLevel, std::string(diagnostic_string.data(), - diagnostic_string.size()))); + // Store the diagnostic for later. + m_diagnostics.push_back(IDAndDiagnostic(DiagLevel, m_output)); } void StoringDiagnosticConsumer::ClearDiagnostics() { m_diagnostics.clear(); } @@ -144,6 +162,15 @@ void StoringDiagnosticConsumer::DumpDiagnostics(Stream &error_stream) { } } +void StoringDiagnosticConsumer::BeginSourceFile( + const clang::LangOptions &LangOpts, const clang::Preprocessor *PP) { + m_diag_printer->BeginSourceFile(LangOpts, PP); +} + +void StoringDiagnosticConsumer::EndSourceFile() { + m_diag_printer->EndSourceFile(); +} + ClangModulesDeclVendor::ClangModulesDeclVendor() : ClangDeclVendor(eClangModuleDeclVendor) {} @@ -159,8 +186,10 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( m_compiler_instance(std::move(compiler_instance)), m_parser(std::move(parser)) { - // Initialize our ClangASTContext. - m_ast_context.reset(new ClangASTContext(m_compiler_instance->getASTContext())); + // Initialize our TypeSystemClang. + m_ast_context = + std::make_unique<TypeSystemClang>("ClangModulesDeclVendor ASTContext", + m_compiler_instance->getASTContext()); } void ClangModulesDeclVendorImpl::ReportModuleExportsHelper( @@ -382,7 +411,7 @@ ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, if (num_matches >= max_matches) return num_matches; - decls.push_back(CompilerDecl(m_ast_context.get(), named_decl)); + decls.push_back(m_ast_context->GetCompilerDecl(named_decl)); ++num_matches; } @@ -601,10 +630,10 @@ ClangModulesDeclVendor::Create(Target &target) { { llvm::SmallString<128> path; - auto props = ModuleList::GetGlobalModuleListProperties(); + const auto &props = ModuleList::GetGlobalModuleListProperties(); props.GetClangModulesCachePath().GetPath(path); std::string module_cache_argument("-fmodules-cache-path="); - module_cache_argument.append(path.str()); + module_cache_argument.append(std::string(path.str())); compiler_invocation_arguments.push_back(module_cache_argument); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index e099b59041d8..f04d1b07f03d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -6,10 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangModulesDeclVendor_h -#define liblldb_ClangModulesDeclVendor_h +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H -#include "lldb/Core/ClangForward.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Platform.h" @@ -113,4 +112,4 @@ public: } // namespace lldb_private -#endif // liblldb_ClangModulesDeclVendor_h +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGMODULESDECLVENDOR_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 41d62a462ab4..42afac9edb0d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -1,4 +1,4 @@ -//===-- ClangPersistentVariables.cpp ----------------------------*- C++ -*-===// +//===-- ClangPersistentVariables.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,9 +7,10 @@ //===----------------------------------------------------------------------===// #include "ClangPersistentVariables.h" +#include "ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" @@ -82,7 +83,7 @@ ClangPersistentVariables::GetCompilerTypeFromPersistentDecl( void ClangPersistentVariables::RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl, - ClangASTContext *ctx) { + TypeSystemClang *ctx) { PersistentDecl p = {decl, ctx}; m_persistent_decls.insert(std::make_pair(name.GetCString(), p)); @@ -99,3 +100,22 @@ clang::NamedDecl * ClangPersistentVariables::GetPersistentDecl(ConstString name) { return m_persistent_decls.lookup(name.GetCString()).m_decl; } + +std::shared_ptr<ClangASTImporter> +ClangPersistentVariables::GetClangASTImporter() { + if (!m_ast_importer_sp) { + m_ast_importer_sp = std::make_shared<ClangASTImporter>(); + } + return m_ast_importer_sp; +} + +ConstString +ClangPersistentVariables::GetNextPersistentVariableName(bool is_error) { + llvm::SmallString<64> name; + { + llvm::raw_svector_ostream os(name); + os << GetPersistentVariablePrefix(is_error) + << m_next_persistent_variable_id++; + } + return ConstString(name); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 434196b35fd5..f888b2d56e68 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangPersistentVariables_h_ -#define liblldb_ClangPersistentVariables_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H #include "llvm/ADT/DenseMap.h" @@ -18,6 +18,9 @@ namespace lldb_private { +class ClangASTImporter; +class TypeSystemClang; + /// \class ClangPersistentVariables ClangPersistentVariables.h /// "lldb/Expression/ClangPersistentVariables.h" Manages persistent values /// that need to be preserved between expression invocations. @@ -36,6 +39,8 @@ public: return pv->getKind() == PersistentExpressionState::eKindClang; } + std::shared_ptr<ClangASTImporter> GetClangASTImporter(); + lldb::ExpressionVariableSP CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) override; @@ -46,9 +51,7 @@ public: void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; - llvm::StringRef GetPersistentVariablePrefix(bool is_error) const override { - return "$"; - } + ConstString GetNextPersistentVariableName(bool is_error = false) override; /// Returns the next file name that should be used for user expressions. std::string GetNextExprFileName() { @@ -63,7 +66,7 @@ public: GetCompilerTypeFromPersistentDecl(ConstString type_name) override; void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl, - ClangASTContext *ctx); + TypeSystemClang *ctx); clang::NamedDecl *GetPersistentDecl(ConstString name); @@ -75,6 +78,12 @@ public: return m_hand_loaded_clang_modules; } +protected: + llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const override { + return "$"; + } + private: /// The counter used by GetNextExprFileName. uint32_t m_next_user_file_id = 0; @@ -84,8 +93,8 @@ private: struct PersistentDecl { /// The persistent decl. clang::NamedDecl *m_decl = nullptr; - /// The ClangASTContext for the ASTContext of m_decl. - ClangASTContext *m_context = nullptr; + /// The TypeSystemClang for the ASTContext of m_decl. + TypeSystemClang *m_context = nullptr; }; typedef llvm::DenseMap<const char *, PersistentDecl> PersistentDeclMap; @@ -96,8 +105,9 @@ private: m_hand_loaded_clang_modules; ///< These are Clang modules we hand-loaded; ///these are the highest- ///< priority source for macros. + std::shared_ptr<ClangASTImporter> m_ast_importer_sp; }; } // namespace lldb_private -#endif // liblldb_ClangPersistentVariables_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGPERSISTENTVARIABLES_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 6698797617a3..a28b4a7fb42c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -1,4 +1,4 @@ -//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===// +//===-- ClangUserExpression.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -20,6 +20,7 @@ #include "ClangUserExpression.h" #include "ASTResultSynthesizer.h" +#include "ClangASTMetadata.h" #include "ClangDiagnostic.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" @@ -27,6 +28,7 @@ #include "ClangPersistentVariables.h" #include "CppModuleConfiguration.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" @@ -37,8 +39,6 @@ #include "lldb/Expression/Materializer.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" @@ -154,7 +154,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { } m_needs_object_ptr = true; } else if (clang::CXXMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) { + TypeSystemClang::DeclContextGetAsCXXMethodDecl(decl_context)) { if (m_allow_cxx && method_decl->isInstance()) { if (m_enforce_valid_object) { lldb::VariableListSP variable_list_sp( @@ -183,7 +183,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { m_needs_object_ptr = true; } } else if (clang::ObjCMethodDecl *method_decl = - ClangASTContext::DeclContextGetAsObjCMethodDecl( + TypeSystemClang::DeclContextGetAsObjCMethodDecl( decl_context)) { if (m_allow_objc) { if (m_enforce_valid_object) { @@ -216,7 +216,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { m_in_static_method = true; } } else if (clang::FunctionDecl *function_decl = - ClangASTContext::DeclContextGetAsFunctionDecl(decl_context)) { + TypeSystemClang::DeclContextGetAsFunctionDecl(decl_context)) { // We might also have a function that said in the debug information that it // captured an object pointer. The best way to deal with getting to the // ivars at present is by pretending that this is a method of a class in @@ -224,7 +224,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { // that here. ClangASTMetadata *metadata = - ClangASTContext::DeclContextGetMetaData(decl_context, function_decl); + TypeSystemClang::DeclContextGetMetaData(decl_context, function_decl); if (metadata && metadata->HasObjectPtr()) { lldb::LanguageType language = metadata->GetObjectPtrLanguage(); if (language == lldb::eLanguageTypeC_plus_plus) { @@ -292,9 +292,9 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { return; } - if (ClangASTContext::IsObjCClassType(self_clang_type)) { + if (TypeSystemClang::IsObjCClassType(self_clang_type)) { return; - } else if (ClangASTContext::IsObjCObjectPointerType( + } else if (TypeSystemClang::IsObjCObjectPointerType( self_clang_type)) { m_in_objectivec_method = true; m_needs_object_ptr = true; @@ -347,50 +347,70 @@ bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_man return true; } -static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) { - if (ClangModulesDeclVendor *decl_vendor = - target->GetClangModulesDeclVendor()) { - auto *persistent_state = llvm::cast<ClangPersistentVariables>( - target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); - if (!persistent_state) - return; - const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = - persistent_state->GetHandLoadedClangModules(); - ClangModulesDeclVendor::ModuleVector modules_for_macros; +static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target, + DiagnosticManager &diagnostic_manager) { + ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor(); + if (!decl_vendor) + return; - for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { - modules_for_macros.push_back(module); - } + if (!target->GetEnableAutoImportClangModules()) + return; - if (target->GetEnableAutoImportClangModules()) { - if (StackFrame *frame = exe_ctx.GetFramePtr()) { - if (Block *block = frame->GetFrameBlock()) { - SymbolContext sc; + auto *persistent_state = llvm::cast<ClangPersistentVariables>( + target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + if (!persistent_state) + return; - block->CalculateSymbolContext(&sc); + StackFrame *frame = exe_ctx.GetFramePtr(); + if (!frame) + return; - if (sc.comp_unit) { - StreamString error_stream; + Block *block = frame->GetFrameBlock(); + if (!block) + return; + SymbolContext sc; - decl_vendor->AddModulesForCompileUnit( - *sc.comp_unit, modules_for_macros, error_stream); - } - } - } - } + block->CalculateSymbolContext(&sc); + + if (!sc.comp_unit) + return; + StreamString error_stream; + + ClangModulesDeclVendor::ModuleVector modules_for_macros = + persistent_state->GetHandLoadedClangModules(); + if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, + error_stream)) + return; + + // Failed to load some modules, so emit the error stream as a diagnostic. + if (!error_stream.Empty()) { + // The error stream already contains several Clang diagnostics that might + // be either errors or warnings, so just print them all as one remark + // diagnostic to prevent that the message starts with "error: error:". + diagnostic_manager.PutString(eDiagnosticSeverityRemark, + error_stream.GetString()); + return; } + + diagnostic_manager.PutString(eDiagnosticSeverityError, + "Unknown error while loading modules needed for " + "current compilation unit."); } -void ClangUserExpression::UpdateLanguageForExpr() { - m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown; - if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) - return; +ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const { + assert(m_options.GetExecutionPolicy() != eExecutionPolicyTopLevel && + "Top level expressions aren't wrapped."); + using Kind = ClangExpressionSourceCode::WrapKind; if (m_in_cplusplus_method) - m_expr_lang = lldb::eLanguageTypeC_plus_plus; - else if (m_in_objectivec_method) - m_expr_lang = lldb::eLanguageTypeObjC; - else - m_expr_lang = lldb::eLanguageTypeC; + return Kind::CppMemberFunction; + else if (m_in_objectivec_method) { + if (m_in_static_method) + return Kind::ObjCStaticMethod; + return Kind::ObjCInstanceMethod; + } + // Not in any kind of 'special' function, so just wrap it in a normal C + // function. + return Kind::Function; } void ClangUserExpression::CreateSourceCode( @@ -404,10 +424,9 @@ void ClangUserExpression::CreateSourceCode( m_transformed_text = m_expr_text; } else { m_source_code.reset(ClangExpressionSourceCode::CreateWrapped( - m_filename, prefix.c_str(), m_expr_text.c_str())); + m_filename, prefix, m_expr_text, GetWrapKind())); - if (!m_source_code->GetText(m_transformed_text, m_expr_lang, - m_in_static_method, exe_ctx, !m_ctx_obj, + if (!m_source_code->GetText(m_transformed_text, exe_ctx, !m_ctx_obj, for_completion, modules_to_import)) { diagnostic_manager.PutString(eDiagnosticSeverityError, "couldn't construct expression body"); @@ -419,7 +438,7 @@ void ClangUserExpression::CreateSourceCode( std::size_t original_start; std::size_t original_end; bool found_bounds = m_source_code->GetOriginalBodyBounds( - m_transformed_text, m_expr_lang, original_start, original_end); + m_transformed_text, original_start, original_end); if (found_bounds) m_user_expression_start_pos = original_start; } @@ -530,7 +549,7 @@ bool ClangUserExpression::PrepareForParsing( ApplyObjcCastHack(m_expr_text); - SetupDeclVendor(exe_ctx, m_target); + SetupDeclVendor(exe_ctx, m_target, diagnostic_manager); CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); llvm::ArrayRef<std::string> imported_modules = @@ -544,7 +563,6 @@ bool ClangUserExpression::PrepareForParsing( llvm::make_range(m_include_directories.begin(), m_include_directories.end())); - UpdateLanguageForExpr(); CreateSourceCode(diagnostic_manager, exe_ctx, imported_modules, for_completion); return true; @@ -577,7 +595,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // Parse the expression // - m_materializer_up.reset(new Materializer()); + m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); @@ -616,15 +634,13 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, if (parser.RewriteExpression(diagnostic_manager)) { size_t fixed_start; size_t fixed_end; - const std::string &fixed_expression = - diagnostic_manager.GetFixedExpression(); + m_fixed_text = diagnostic_manager.GetFixedExpression(); // Retrieve the original expression in case we don't have a top level // expression (which has no surrounding source code). - if (m_source_code && - m_source_code->GetOriginalBodyBounds(fixed_expression, m_expr_lang, - fixed_start, fixed_end)) + if (m_source_code && m_source_code->GetOriginalBodyBounds( + m_fixed_text, fixed_start, fixed_end)) m_fixed_text = - fixed_expression.substr(fixed_start, fixed_end - fixed_start); + m_fixed_text.substr(fixed_start, fixed_end - fixed_start); } } return false; @@ -659,7 +675,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, const char *error_cstr = static_init_error.AsCString(); if (error_cstr && error_cstr[0]) diagnostic_manager.Printf(eDiagnosticSeverityError, - "couldn't run static initializers: %s\n", + "%s\n", error_cstr); else diagnostic_manager.PutString(eDiagnosticSeverityError, @@ -767,7 +783,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, // Parse the expression // - m_materializer_up.reset(new Materializer()); + m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true); @@ -896,16 +912,23 @@ void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap( Materializer::PersistentVariableDelegate &delegate, bool keep_result_in_memory, ValueObject *ctx_obj) { - m_expr_decl_map_up.reset(new ClangExpressionDeclMap( - keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), - exe_ctx.GetTargetRef().GetClangASTImporter(), ctx_obj)); + std::shared_ptr<ClangASTImporter> ast_importer; + auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC); + if (state) { + auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); + ast_importer = persistent_vars->GetClangASTImporter(); + } + m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( + keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), ast_importer, + ctx_obj); } clang::ASTConsumer * ClangUserExpression::ClangUserExpressionHelper::ASTTransformer( clang::ASTConsumer *passthrough) { - m_result_synthesizer_up.reset( - new ASTResultSynthesizer(passthrough, m_top_level, m_target)); + m_result_synthesizer_up = std::make_unique<ASTResultSynthesizer>( + passthrough, m_top_level, m_target); return m_result_synthesizer_up.get(); } @@ -917,9 +940,7 @@ void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() { } ConstString ClangUserExpression::ResultDelegate::GetName() { - auto prefix = m_persistent_state->GetPersistentVariablePrefix(); - return m_persistent_state->GetNextPersistentVariableName(*m_target_sp, - prefix); + return m_persistent_state->GetNextPersistentVariableName(false); } void ClangUserExpression::ResultDelegate::DidDematerialize( diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 00cbffa7fd6f..f734069655ef 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangUserExpression_h_ -#define liblldb_ClangUserExpression_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H #include <vector> @@ -20,7 +20,6 @@ #include "IRForTarget.h" #include "lldb/Core/Address.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/LLVMUserExpression.h" #include "lldb/Expression/Materializer.h" #include "lldb/Target/ExecutionContext.h" @@ -186,7 +185,8 @@ private: ExecutionContext &exe_ctx, std::vector<std::string> modules_to_import, bool for_completion); - void UpdateLanguageForExpr(); + /// Defines how the current expression should be wrapped. + ClangExpressionSourceCode::WrapKind GetWrapKind() const; bool SetupPersistentState(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx); bool PrepareForParsing(DiagnosticManager &diagnostic_manager, @@ -209,8 +209,6 @@ private: lldb::TargetSP m_target_sp; }; - /// The language type of the current expression. - lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown; /// The include directories that should be used when parsing the expression. std::vector<std::string> m_include_directories; @@ -251,4 +249,4 @@ private: } // namespace lldb_private -#endif // liblldb_ClangUserExpression_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUSEREXPRESSION_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp new file mode 100644 index 000000000000..a7f5dce8558f --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp @@ -0,0 +1,87 @@ +//===-- ClangUtil.cpp -----------------------------------------------------===// +// +// 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 +// +// A collection of helper methods and data structures for manipulating clang +// types and decls. +//===----------------------------------------------------------------------===// + +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + +using namespace clang; +using namespace lldb_private; + +bool ClangUtil::IsClangType(const CompilerType &ct) { + // Invalid types are never Clang types. + if (!ct) + return false; + + if (llvm::dyn_cast_or_null<TypeSystemClang>(ct.GetTypeSystem()) == nullptr) + return false; + + if (!ct.GetOpaqueQualType()) + return false; + + return true; +} + +clang::Decl *ClangUtil::GetDecl(const CompilerDecl &decl) { + assert(llvm::isa<TypeSystemClang>(decl.GetTypeSystem())); + return static_cast<clang::Decl *>(decl.GetOpaqueDecl()); +} + +QualType ClangUtil::GetQualType(const CompilerType &ct) { + // Make sure we have a clang type before making a clang::QualType + if (!IsClangType(ct)) + return QualType(); + + return QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); +} + +QualType ClangUtil::GetCanonicalQualType(const CompilerType &ct) { + if (!IsClangType(ct)) + return QualType(); + + return GetQualType(ct).getCanonicalType(); +} + +CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) { + if (!IsClangType(ct)) + return ct; + + QualType qual_type(GetQualType(ct)); + qual_type.removeLocalFastQualifiers(); + return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr()); +} + +clang::TagDecl *ClangUtil::GetAsTagDecl(const CompilerType &type) { + clang::QualType qual_type = ClangUtil::GetCanonicalQualType(type); + if (qual_type.isNull()) + return nullptr; + + return qual_type->getAsTagDecl(); +} + +std::string ClangUtil::DumpDecl(const clang::Decl *d) { + if (!d) + return "nullptr"; + + std::string result; + llvm::raw_string_ostream stream(result); + bool deserialize = false; + d->dump(stream, deserialize); + + stream.flush(); + return result; +} + +std::string ClangUtil::ToString(const clang::Type *t) { + return clang::QualType(t, 0).getAsString(); +} + +std::string ClangUtil::ToString(const CompilerType &c) { + return ClangUtil::GetQualType(c).getAsString(); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h new file mode 100644 index 000000000000..50cae42bc7c2 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h @@ -0,0 +1,50 @@ +//===-- ClangUtil.h ---------------------------------------------*- 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 +// +// A collection of helper methods and data structures for manipulating clang +// types and decls. +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTIL_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTIL_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Type.h" + +#include "lldb/Symbol/CompilerType.h" + +namespace clang { +class TagDecl; +} + +namespace lldb_private { +struct ClangUtil { + static bool IsClangType(const CompilerType &ct); + + /// Returns the clang::Decl of the given CompilerDecl. + /// CompilerDecl has to be valid and represent a clang::Decl. + static clang::Decl *GetDecl(const CompilerDecl &decl); + + static clang::QualType GetQualType(const CompilerType &ct); + + static clang::QualType GetCanonicalQualType(const CompilerType &ct); + + static CompilerType RemoveFastQualifiers(const CompilerType &ct); + + static clang::TagDecl *GetAsTagDecl(const CompilerType &type); + + /// Returns a textual representation of the given Decl's AST. Does not + /// deserialize any child nodes. + static std::string DumpDecl(const clang::Decl *d); + /// Returns a textual representation of the given type. + static std::string ToString(const clang::Type *t); + /// Returns a textual representation of the given CompilerType (assuming + /// its underlying type is a Clang type). + static std::string ToString(const CompilerType &c); +}; +} + +#endif diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 199e4898e118..25ec982220a0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -1,4 +1,4 @@ -//===-- ClangUtilityFunction.cpp ---------------------------------*- C++-*-===// +//===-- ClangUtilityFunction.cpp ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,6 +12,7 @@ #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" #include "ClangExpressionSourceCode.h" +#include "ClangPersistentVariables.h" #include <stdio.h> #if HAVE_SYS_TYPES_H @@ -159,7 +160,14 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap( ExecutionContext &exe_ctx, bool keep_result_in_memory) { - m_expr_decl_map_up.reset(new ClangExpressionDeclMap( - keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), - exe_ctx.GetTargetRef().GetClangASTImporter(), nullptr)); + std::shared_ptr<ClangASTImporter> ast_importer; + auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC); + if (state) { + auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); + ast_importer = persistent_vars->GetClangASTImporter(); + } + m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( + keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer, + nullptr); } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 9efaa0254c3e..1f2dd5fdbecc 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ClangUtilityFunction_h_ -#define liblldb_ClangUtilityFunction_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H #include <map> #include <string> @@ -15,7 +15,6 @@ #include "ClangExpressionHelper.h" -#include "lldb/Core/ClangForward.h" #include "lldb/Expression/UtilityFunction.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" @@ -107,4 +106,4 @@ private: } // namespace lldb_private -#endif // liblldb_ClangUtilityFunction_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGUTILITYFUNCTION_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp index 51ae73285b53..f1272c67d20f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -73,7 +73,7 @@ CppModuleConfiguration::CppModuleConfiguration( llvm::SmallString<256> resource_dir; llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(), "include"); - m_resource_inc = resource_dir.str(); + m_resource_inc = std::string(resource_dir.str()); // This order matches the way Clang orders these directories. m_include_dirs = {m_std_inc.Get(), m_resource_inc, m_c_inc.Get()}; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h index 8e892e37d0de..235ac2bd090c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_CppModuleConfiguration_h_ -#define liblldb_CppModuleConfiguration_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CPPMODULECONFIGURATION_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CPPMODULECONFIGURATION_H #include <lldb/Core/FileSpecList.h> #include <llvm/Support/Regex.h> @@ -56,7 +56,7 @@ class CppModuleConfiguration { bool analyzeFile(const FileSpec &f); public: - /// Creates a configuraiton by analyzing the given list of used source files. + /// Creates a configuration by analyzing the given list of used source files. /// /// Currently only looks at the used paths and doesn't actually access the /// files on the disk. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp new file mode 100644 index 000000000000..2f8cf1846ee7 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -0,0 +1,289 @@ +//===-- CxxModuleHandler.cpp ----------------------------------------------===// +// +// 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 "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.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(TypeSystemClang::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 = std::make_unique<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 list 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); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h new file mode 100644 index 000000000000..6490af7f8978 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h @@ -0,0 +1,65 @@ +//===-- CxxModuleHandler.h --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H + +#include "clang/AST/ASTImporter.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/StringSet.h" + +namespace lldb_private { + +/// Handles importing decls into an ASTContext with an attached C++ module. +/// +/// This class searches a C++ module (which must be attached to the target +/// ASTContext) for an equivalent decl to the one that should be imported. +/// If the decl that is found in the module is a suitable replacement +/// for the decl that should be imported, the module decl will be treated as +/// the result of the import process. +/// +/// If the Decl that should be imported is a template specialization +/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`), +/// then this class tries to create the template specialization in the target +/// ASTContext. This is only possible if the CxxModuleHandler can determine +/// that instantiating this template is safe to do, e.g. because the target +/// decl is a container class from the STL. +class CxxModuleHandler { + /// The ASTImporter that should be used to import any Decls which aren't + /// directly handled by this class itself. + clang::ASTImporter *m_importer = nullptr; + + /// The Sema instance of the target ASTContext. + clang::Sema *m_sema = nullptr; + + /// List of template names this class currently supports. These are the + /// template names inside the 'std' namespace such as 'vector' or 'list'. + llvm::StringSet<> m_supported_templates; + + /// Tries to manually instantiate the given foreign template in the target + /// context (designated by m_sema). + llvm::Optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d); + +public: + CxxModuleHandler() = default; + CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target); + + /// Attempts to import the given decl into the target ASTContext by + /// deserializing it from the 'std' module. This function returns a Decl if a + /// Decl has been deserialized from the 'std' module. Otherwise this function + /// returns nothing. + llvm::Optional<clang::Decl *> Import(clang::Decl *d); + + /// Returns true iff this instance is capable of importing any declarations + /// in the target ASTContext. + bool isValid() const { return m_sema != nullptr; } +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CXXMODULEHANDLER_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp index d5ffb9529f36..b92f00ec2b63 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -1,4 +1,4 @@ -//===-- IRDynamicChecks.cpp -------------------------------------*- C++ -*-===// +//===-- IRDynamicChecks.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -181,8 +181,8 @@ protected: /// /// \param[in] inst /// The instruction to be instrumented. - void RegisterInstruction(llvm::Instruction &i) { - m_to_instrument.push_back(&i); + void RegisterInstruction(llvm::Instruction &inst) { + m_to_instrument.push_back(&inst); } /// Determine whether a single instruction is interesting to instrument, @@ -465,7 +465,7 @@ protected: } static llvm::Function *GetCalledFunction(llvm::CallInst *inst) { - return GetFunction(inst->getCalledValue()); + return GetFunction(inst->getCalledOperand()); } bool InspectInstruction(llvm::Instruction &i) override { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h index 5b9c8007ab76..a4de527e4512 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_IRDynamicChecks_h_ -#define liblldb_IRDynamicChecks_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H #include "lldb/Expression/DynamicCheckerFunctions.h" #include "lldb/lldb-types.h" @@ -124,4 +124,4 @@ private: } // namespace lldb_private -#endif // liblldb_IRDynamicChecks_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRDYNAMICCHECKS_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 103a7ee46f35..8511e554509a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -1,4 +1,4 @@ -//===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===// +//===-- IRForTarget.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,7 +9,9 @@ #include "IRForTarget.h" #include "ClangExpressionDeclMap.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InstrTypes.h" @@ -27,8 +29,6 @@ #include "lldb/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataBufferHeap.h" @@ -283,17 +283,13 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { clang::QualType element_qual_type = pointer_pointertype->getPointeeType(); m_result_type = lldb_private::TypeFromParser( - element_qual_type.getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext( - &result_decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(element_qual_type)); } else if (pointer_objcobjpointertype) { clang::QualType element_qual_type = clang::QualType(pointer_objcobjpointertype->getObjectType(), 0); m_result_type = lldb_private::TypeFromParser( - element_qual_type.getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext( - &result_decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(element_qual_type)); } else { LLDB_LOG(log, "Expected result to have pointer type, but it did not"); @@ -305,9 +301,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { } } else { m_result_type = lldb_private::TypeFromParser( - result_var->getType().getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext( - &result_decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(result_var->getType())); } lldb::TargetSP target_sp(m_execution_unit.GetTarget()); @@ -433,7 +427,7 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str, m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str, missing_weak); if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS || missing_weak) { - log->PutCString("Couldn't find CFStringCreateWithBytes in the target"); + LLDB_LOG(log, "Couldn't find CFStringCreateWithBytes in the target"); m_error_stream.Printf("Error [IRForTarget]: Rewriting an Objective-C " "constant string requires " @@ -823,7 +817,8 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) { if (!omvn_initializer_array->isString()) return false; - std::string omvn_initializer_string = omvn_initializer_array->getAsString(); + std::string omvn_initializer_string = + std::string(omvn_initializer_array->getAsString()); LLDB_LOG(log, "Found Objective-C selector reference \"{0}\"", omvn_initializer_string); @@ -981,7 +976,8 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) { if (!ocn_initializer_array->isString()) return false; - std::string ocn_initializer_string = ocn_initializer_array->getAsString(); + std::string ocn_initializer_string = + std::string(ocn_initializer_array->getAsString()); LLDB_LOG(log, "Found Objective-C class reference \"{0}\"", ocn_initializer_string); @@ -1092,8 +1088,7 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr); lldb_private::TypeFromParser result_decl_type( - decl->getType().getAsOpaquePtr(), - lldb_private::ClangASTContext::GetASTContext(&decl->getASTContext())); + m_decl_map->GetTypeSystem()->GetType(decl->getType())); StringRef decl_name(decl->getName()); lldb_private::ConstString persistent_variable_name(decl_name.data(), @@ -1125,7 +1120,9 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) { // Now, since the variable is a pointer variable, we will drop in a load of // that pointer variable. - LoadInst *persistent_load = new LoadInst(persistent_global, "", alloc); + LoadInst *persistent_load = + new LoadInst(persistent_global->getType()->getPointerElementType(), + persistent_global, "", alloc); LLDB_LOG(log, "Replacing \"{0}\" with \"{1}\"", PrintValue(alloc), PrintValue(persistent_load)); @@ -1223,10 +1220,8 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { if (value_decl == nullptr) return false; - lldb_private::CompilerType compiler_type( - lldb_private::ClangASTContext::GetASTContext( - &value_decl->getASTContext()), - value_decl->getType().getAsOpaquePtr()); + lldb_private::CompilerType compiler_type = + m_decl_map->GetTypeSystem()->GetType(value_decl->getType()); const Type *value_type = nullptr; @@ -1400,7 +1395,7 @@ bool IRForTarget::RemoveCXAAtExit(BasicBlock &basic_block) { if (func && func->getName() == "__cxa_atexit") remove = true; - llvm::Value *val = call->getCalledValue(); + llvm::Value *val = call->getCalledOperand(); if (val && val->getName() == "__cxa_atexit") remove = true; @@ -1799,7 +1794,9 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { get_element_ptr, value->getType()->getPointerTo(), "", entry_instruction); - LoadInst *load = new LoadInst(bit_cast, "", entry_instruction); + LoadInst *load = + new LoadInst(bit_cast->getType()->getPointerElementType(), + bit_cast, "", entry_instruction); return load; } else { @@ -1845,7 +1842,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) { lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); m_module = &llvm_module; - m_target_data.reset(new DataLayout(m_module)); + m_target_data = std::make_unique<DataLayout>(m_module); m_intptr_ty = llvm::Type::getIntNTy(m_module->getContext(), m_target_data->getPointerSizeInBits()); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h index 262e8ee0c06c..ebfc0cae626c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -7,10 +7,9 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_IRForTarget_h_ -#define liblldb_IRForTarget_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H -#include "lldb/Core/ClangForward.h" #include "lldb/Symbol/TaggedASTType.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" @@ -38,6 +37,10 @@ class DataLayout; class Value; } +namespace clang { +class NamedDecl; +} + namespace lldb_private { class ClangExpressionDeclMap; class IRExecutionUnit; @@ -506,4 +509,4 @@ private: bool CompleteDataAllocation(); }; -#endif // liblldb_IRForTarget_h_ +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_IRFORTARGET_H diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h index 7553860f2492..b7b6640c4810 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ModuleDependencyCollector_h_ -#define liblldb_ModuleDependencyCollector_h_ +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_MODULEDEPENDENCYCOLLECTOR_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_MODULEDEPENDENCYCOLLECTOR_H #include "clang/Frontend/Utils.h" #include "llvm/ADT/StringRef.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp new file mode 100644 index 000000000000..c1f88889f1dc --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -0,0 +1,179 @@ +//===-- NameSearchContext.cpp ---------------------------------------------===// +// +// 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 "NameSearchContext.h" +#include "ClangUtil.h" + +using namespace clang; +using namespace lldb_private; + +clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) { + assert(type && "Type for variable must be valid!"); + + if (!type.IsValid()) + return nullptr; + + TypeSystemClang *lldb_ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!lldb_ast) + return nullptr; + + IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); + + clang::ASTContext &ast = lldb_ast->getASTContext(); + + clang::NamedDecl *Decl = VarDecl::Create( + ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(), + SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static); + m_decls.push_back(Decl); + + return Decl; +} + +clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, + bool extern_c) { + assert(type && "Type for variable must be valid!"); + + if (!type.IsValid()) + return nullptr; + + if (m_function_types.count(type)) + return nullptr; + + TypeSystemClang *lldb_ast = + llvm::dyn_cast<TypeSystemClang>(type.GetTypeSystem()); + if (!lldb_ast) + return nullptr; + + m_function_types.insert(type); + + QualType qual_type(ClangUtil::GetQualType(type)); + + clang::ASTContext &ast = lldb_ast->getASTContext(); + + const bool isInlineSpecified = false; + const bool hasWrittenPrototype = true; + const bool isConstexprSpecified = false; + + clang::DeclContext *context = const_cast<DeclContext *>(m_decl_context); + + if (extern_c) { + context = LinkageSpecDecl::Create( + ast, context, SourceLocation(), SourceLocation(), + clang::LinkageSpecDecl::LanguageIDs::lang_c, false); + } + + // Pass the identifier info for functions the decl_name is needed for + // operators + clang::DeclarationName decl_name = + m_decl_name.getNameKind() == DeclarationName::Identifier + ? m_decl_name.getAsIdentifierInfo() + : m_decl_name; + + clang::FunctionDecl *func_decl = FunctionDecl::Create( + ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, + nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, + isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + + // We have to do more than just synthesize the FunctionDecl. We have to + // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do + // this, we raid the function's FunctionProtoType for types. + + const FunctionProtoType *func_proto_type = + qual_type.getTypePtr()->getAs<FunctionProtoType>(); + + if (func_proto_type) { + unsigned NumArgs = func_proto_type->getNumParams(); + unsigned ArgIndex; + + SmallVector<ParmVarDecl *, 5> parm_var_decls; + + for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex) { + QualType arg_qual_type(func_proto_type->getParamType(ArgIndex)); + + parm_var_decls.push_back( + ParmVarDecl::Create(ast, const_cast<DeclContext *>(context), + SourceLocation(), SourceLocation(), nullptr, + arg_qual_type, nullptr, SC_Static, nullptr)); + } + + func_decl->setParams(ArrayRef<ParmVarDecl *>(parm_var_decls)); + } else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + LLDB_LOG(log, "Function type wasn't a FunctionProtoType"); + } + + // If this is an operator (e.g. operator new or operator==), only insert the + // declaration we inferred from the symbol if we can provide the correct + // number of arguments. We shouldn't really inject random decl(s) for + // functions that are analyzed semantically in a special way, otherwise we + // will crash in clang. + clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; + if (func_proto_type && + TypeSystemClang::IsOperator(decl_name.getAsString().c_str(), op_kind)) { + if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( + false, op_kind, func_proto_type->getNumParams())) + return nullptr; + } + m_decls.push_back(func_decl); + + return func_decl; +} + +clang::NamedDecl *NameSearchContext::AddGenericFunDecl() { + FunctionProtoType::ExtProtoInfo proto_info; + + proto_info.Variadic = true; + + QualType generic_function_type( + GetASTContext().getFunctionType(GetASTContext().UnknownAnyTy, // result + ArrayRef<QualType>(), // argument types + proto_info)); + + return AddFunDecl(m_clang_ts.GetType(generic_function_type), true); +} + +clang::NamedDecl * +NameSearchContext::AddTypeDecl(const CompilerType &clang_type) { + if (ClangUtil::IsClangType(clang_type)) { + QualType qual_type = ClangUtil::GetQualType(clang_type); + + if (const TypedefType *typedef_type = + llvm::dyn_cast<TypedefType>(qual_type)) { + TypedefNameDecl *typedef_name_decl = typedef_type->getDecl(); + + m_decls.push_back(typedef_name_decl); + + return (NamedDecl *)typedef_name_decl; + } else if (const TagType *tag_type = qual_type->getAs<TagType>()) { + TagDecl *tag_decl = tag_type->getDecl(); + + m_decls.push_back(tag_decl); + + return tag_decl; + } else if (const ObjCObjectType *objc_object_type = + qual_type->getAs<ObjCObjectType>()) { + ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface(); + + m_decls.push_back((NamedDecl *)interface_decl); + + return (NamedDecl *)interface_decl; + } + } + return nullptr; +} + +void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) { + for (clang::NamedDecl *decl : result) + m_decls.push_back(decl); +} + +void NameSearchContext::AddNamedDecl(clang::NamedDecl *decl) { + m_decls.push_back(decl); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h new file mode 100644 index 000000000000..dc8621dd6aba --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h @@ -0,0 +1,124 @@ +//===-- NameSearchContext.h -------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H +#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/Symbol/CompilerType.h" +#include "llvm/ADT/SmallSet.h" + +namespace lldb_private { + +/// \class NameSearchContext ClangASTSource.h +/// "lldb/Expression/ClangASTSource.h" Container for all objects relevant to a +/// single name lookup +/// +/// LLDB needs to create Decls for entities it finds. This class communicates +/// what name is being searched for and provides helper functions to construct +/// Decls given appropriate type information. +struct NameSearchContext { + /// The type system of the AST from which the lookup originated. + TypeSystemClang &m_clang_ts; + /// The list of declarations already constructed. + llvm::SmallVectorImpl<clang::NamedDecl *> &m_decls; + /// The mapping of all namespaces found for this request back to their + /// modules. + ClangASTImporter::NamespaceMapSP m_namespace_map; + /// The name being looked for. + const clang::DeclarationName m_decl_name; + /// The DeclContext to put declarations into. + const clang::DeclContext *m_decl_context; + /// All the types of functions that have been reported, so we don't + /// report conflicts. + llvm::SmallSet<CompilerType, 5> m_function_types; + + bool m_found_variable = false; + bool m_found_function_with_type_info = false; + bool m_found_function = false; + bool m_found_local_vars_nsp = false; + bool m_found_type = false; + + /// Constructor + /// + /// Initializes class variables. + /// + /// \param[in] clang_ts + /// The TypeSystemClang from which the request originates. + /// + /// \param[in] decls + /// A reference to a list into which new Decls will be placed. This + /// list is typically empty when the function is called. + /// + /// \param[in] name + /// The name being searched for (always an Identifier). + /// + /// \param[in] dc + /// The DeclContext to register Decls in. + NameSearchContext(TypeSystemClang &clang_ts, + llvm::SmallVectorImpl<clang::NamedDecl *> &decls, + clang::DeclarationName name, const clang::DeclContext *dc) + : m_clang_ts(clang_ts), m_decls(decls), + m_namespace_map(std::make_shared<ClangASTImporter::NamespaceMap>()), + m_decl_name(name), m_decl_context(dc) { + ; + } + + /// Create a VarDecl with the name being searched for and the provided type + /// and register it in the right places. + /// + /// \param[in] type + /// The opaque QualType for the VarDecl being registered. + clang::NamedDecl *AddVarDecl(const CompilerType &type); + + /// Create a FunDecl with the name being searched for and the provided type + /// and register it in the right places. + /// + /// \param[in] type + /// The opaque QualType for the FunDecl being registered. + /// + /// \param[in] extern_c + /// If true, build an extern "C" linkage specification for this. + clang::NamedDecl *AddFunDecl(const CompilerType &type, bool extern_c = false); + + /// Create a FunDecl with the name being searched for and generic type (i.e. + /// intptr_t NAME_GOES_HERE(...)) and register it in the right places. + clang::NamedDecl *AddGenericFunDecl(); + + /// Create a TypeDecl with the name being searched for and the provided type + /// and register it in the right places. + /// + /// \param[in] compiler_type + /// The opaque QualType for the TypeDecl being registered. + clang::NamedDecl *AddTypeDecl(const CompilerType &compiler_type); + + /// Add Decls from the provided DeclContextLookupResult to the list of + /// results. + /// + /// \param[in] result + /// The DeclContextLookupResult, usually returned as the result + /// of querying a DeclContext. + void AddLookupResult(clang::DeclContextLookupResult result); + + /// Add a NamedDecl to the list of results. + /// + /// \param[in] decl + /// The NamedDecl, usually returned as the result + /// of querying a DeclContext. + void AddNamedDecl(clang::NamedDecl *decl); + +private: + clang::ASTContext &GetASTContext() const { + return m_clang_ts.getASTContext(); + } +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_NAME_SEARCH_CONTEXT_H |