summaryrefslogtreecommitdiff
path: root/source/Plugins/ExpressionParser
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:51:52 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:51:52 +0000
commit5f29bb8a675e8f96452b632e7129113f7dec850e (patch)
tree3d3f2a0d3ad10872a4dcaba8ec8d1d20c87ab147 /source/Plugins/ExpressionParser
parent88c643b6fec27eec436c8d138fee6346e92337d6 (diff)
Notes
Diffstat (limited to 'source/Plugins/ExpressionParser')
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTDumper.cpp9
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTDumper.h7
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp27
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h77
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp19
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h53
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTUtils.cpp26
-rw-r--r--source/Plugins/ExpressionParser/Clang/ASTUtils.h579
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp168
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangASTSource.h199
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h9
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp117
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h271
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h17
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp385
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h80
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp497
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h71
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp11
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h57
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp11
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h46
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangHost.cpp101
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangHost.h13
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp115
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h47
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp33
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h22
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp195
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUserExpression.h78
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp34
-rw-r--r--source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h28
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp595
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h131
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRForTarget.cpp96
-rw-r--r--source/Plugins/ExpressionParser/Clang/IRForTarget.h278
-rw-r--r--source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h38
37 files changed, 3236 insertions, 1304 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
index 0d619e4174e0..369f88327dd9 100644
--- a/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.cpp
@@ -1,9 +1,8 @@
//===-- ASTDumper.cpp -------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -86,7 +85,7 @@ void ASTDumper::ToLog(Log *log, const char *prefix) {
memcpy(str, m_dump.c_str(), len);
- char *end = NULL;
+ char *end = nullptr;
end = strchr(str, '\n');
diff --git a/source/Plugins/ExpressionParser/Clang/ASTDumper.h b/source/Plugins/ExpressionParser/Clang/ASTDumper.h
index 58ba19739e5b..ddf055d9c0c3 100644
--- a/source/Plugins/ExpressionParser/Clang/ASTDumper.h
+++ b/source/Plugins/ExpressionParser/Clang/ASTDumper.h
@@ -1,9 +1,8 @@
//===-- ASTDumper.h ---------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
index c2bc18a04e95..526ef90782ef 100644
--- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp
@@ -1,9 +1,8 @@
//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -35,8 +34,9 @@ using namespace lldb_private;
ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
bool top_level, Target &target)
- : m_ast_context(NULL), m_passthrough(passthrough), m_passthrough_sema(NULL),
- m_target(target), m_sema(NULL), m_top_level(top_level) {
+ : m_ast_context(nullptr), m_passthrough(passthrough),
+ m_passthrough_sema(nullptr), m_target(target), m_sema(nullptr),
+ m_top_level(top_level) {
if (!m_passthrough)
return;
@@ -239,7 +239,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
break;
last_expr = implicit_cast->getSubExpr();
- } while (0);
+ } while (false);
// is_lvalue is used to record whether the expression returns an assignable
// Lvalue or an Rvalue. This is relevant because they are handled
@@ -312,7 +312,7 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
(is_lvalue ? "lvalue" : "rvalue"), s.c_str());
}
- clang::VarDecl *result_decl = NULL;
+ clang::VarDecl *result_decl = nullptr;
if (is_lvalue) {
IdentifierInfo *result_ptr_id;
@@ -330,14 +330,14 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
QualType ptr_qual_type;
- if (expr_qual_type->getAs<ObjCObjectType>() != NULL)
+ if (expr_qual_type->getAs<ObjCObjectType>() != nullptr)
ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
else
ptr_qual_type = Ctx.getPointerType(expr_qual_type);
result_decl =
VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(),
- result_ptr_id, ptr_qual_type, NULL, SC_Static);
+ result_ptr_id, ptr_qual_type, nullptr, SC_Static);
if (!result_decl)
return false;
@@ -351,8 +351,9 @@ bool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
} else {
IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
- result_decl = VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(),
- &result_id, expr_qual_type, NULL, SC_Static);
+ result_decl =
+ VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id,
+ expr_qual_type, nullptr, SC_Static);
if (!result_decl)
return false;
@@ -508,7 +509,7 @@ void ASTResultSynthesizer::InitializeSema(Sema &S) {
}
void ASTResultSynthesizer::ForgetSema() {
- m_sema = NULL;
+ m_sema = nullptr;
if (m_passthrough_sema)
m_passthrough_sema->ForgetSema();
diff --git a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
index 859a1dfa5f73..670ba6dce72e 100644
--- a/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
+++ b/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h
@@ -1,9 +1,8 @@
//===-- ASTResultSynthesizer.h ----------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -16,8 +15,7 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ASTResultSynthesizer ASTResultSynthesizer.h
+/// \class ASTResultSynthesizer ASTResultSynthesizer.h
/// "lldb/Expression/ASTResultSynthesizer.h" Adds a result variable
/// declaration to the ASTs for an expression.
///
@@ -29,165 +27,126 @@ namespace lldb_private {
/// ASTResultSynthesizer's job is to add the variable and its initialization
/// to the ASTs for the expression, and it does so by acting as a SemaConsumer
/// for Clang.
-//----------------------------------------------------------------------
class ASTResultSynthesizer : public clang::SemaConsumer {
public:
- //----------------------------------------------------------------------
/// Constructor
///
- /// @param[in] passthrough
+ /// \param[in] passthrough
/// Since the ASTs must typically go through to the Clang code generator
/// in order to produce LLVM IR, this SemaConsumer must allow them to
/// pass to the next step in the chain after processing. Passthrough is
/// the next ASTConsumer, or NULL if none is required.
///
- /// @param[in] top_level
+ /// \param[in] top_level
/// If true, register all top-level Decls and don't try to handle the
/// main function.
///
- /// @param[in] target
+ /// \param[in] target
/// The target, which contains the persistent variable store and the
/// AST importer.
- //----------------------------------------------------------------------
ASTResultSynthesizer(clang::ASTConsumer *passthrough, bool top_level,
Target &target);
- //----------------------------------------------------------------------
/// Destructor
- //----------------------------------------------------------------------
~ASTResultSynthesizer() override;
- //----------------------------------------------------------------------
/// Link this consumer with a particular AST context
///
- /// @param[in] Context
+ /// \param[in] Context
/// This AST context will be used for types and identifiers, and also
/// forwarded to the passthrough consumer, if one exists.
- //----------------------------------------------------------------------
void Initialize(clang::ASTContext &Context) override;
- //----------------------------------------------------------------------
/// Examine a list of Decls to find the function $__lldb_expr and transform
/// its code
///
- /// @param[in] D
+ /// \param[in] D
/// The list of Decls to search. These may contain LinkageSpecDecls,
/// which need to be searched recursively. That job falls to
/// TransformTopLevelDecl.
- //----------------------------------------------------------------------
bool HandleTopLevelDecl(clang::DeclGroupRef D) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void HandleTranslationUnit(clang::ASTContext &Ctx) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void HandleTagDeclDefinition(clang::TagDecl *D) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void CompleteTentativeDefinition(clang::VarDecl *D) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void HandleVTable(clang::CXXRecordDecl *RD) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void PrintStats() override;
- //----------------------------------------------------------------------
/// Set the Sema object to use when performing transforms, and pass it on
///
- /// @param[in] S
+ /// \param[in] S
/// The Sema to use. Because Sema isn't externally visible, this class
/// casts it to an Action for actual use.
- //----------------------------------------------------------------------
void InitializeSema(clang::Sema &S) override;
- //----------------------------------------------------------------------
/// Reset the Sema to NULL now that transformations are done
- //----------------------------------------------------------------------
void ForgetSema() override;
- //----------------------------------------------------------------------
/// The parse has succeeded, so record its persistent decls
- //----------------------------------------------------------------------
void CommitPersistentDecls();
private:
- //----------------------------------------------------------------------
/// Hunt the given Decl for FunctionDecls named $__lldb_expr, recursing as
/// necessary through LinkageSpecDecls, and calling SynthesizeResult on
/// anything that was found
///
- /// @param[in] D
+ /// \param[in] D
/// The Decl to hunt.
- //----------------------------------------------------------------------
void TransformTopLevelDecl(clang::Decl *D);
- //----------------------------------------------------------------------
/// Process an Objective-C method and produce the result variable and
/// initialization
///
- /// @param[in] MethodDecl
+ /// \param[in] MethodDecl
/// The method to process.
- //----------------------------------------------------------------------
bool SynthesizeObjCMethodResult(clang::ObjCMethodDecl *MethodDecl);
- //----------------------------------------------------------------------
/// Process a function and produce the result variable and initialization
///
- /// @param[in] FunDecl
+ /// \param[in] FunDecl
/// The function to process.
- //----------------------------------------------------------------------
bool SynthesizeFunctionResult(clang::FunctionDecl *FunDecl);
- //----------------------------------------------------------------------
/// Process a function body and produce the result variable and
/// initialization
///
- /// @param[in] Body
+ /// \param[in] Body
/// The body of the function.
///
- /// @param[in] DC
+ /// \param[in] DC
/// The DeclContext of the function, into which the result variable
/// is inserted.
- //----------------------------------------------------------------------
bool SynthesizeBodyResult(clang::CompoundStmt *Body, clang::DeclContext *DC);
- //----------------------------------------------------------------------
/// Given a DeclContext for a function or method, find all types declared in
/// the context and record any persistent types found.
///
- /// @param[in] FunDeclCtx
+ /// \param[in] FunDeclCtx
/// The context for the function to process.
- //----------------------------------------------------------------------
void RecordPersistentTypes(clang::DeclContext *FunDeclCtx);
- //----------------------------------------------------------------------
/// Given a TypeDecl, if it declares a type whose name starts with a dollar
/// sign, register it as a pointer type in the target's scratch
/// AST context.
///
- /// @param[in] Body
+ /// \param[in] Body
/// The body of the function.
- //----------------------------------------------------------------------
void MaybeRecordPersistentType(clang::TypeDecl *D);
- //----------------------------------------------------------------------
/// Given a NamedDecl, register it as a pointer type in the target's scratch
/// AST context.
///
- /// @param[in] Body
+ /// \param[in] Body
/// The body of the function.
- //----------------------------------------------------------------------
void RecordPersistentDecl(clang::NamedDecl *D);
clang::ASTContext
diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
index 2faeecdf724e..190eacaa2b62 100644
--- a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp
@@ -1,9 +1,8 @@
//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -30,9 +29,9 @@ using namespace lldb_private;
ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
const char *struct_name,
ClangFunctionCaller &function)
- : m_ast_context(NULL), m_passthrough(passthrough), m_passthrough_sema(NULL),
- m_sema(NULL), m_action(NULL), m_function(function),
- m_struct_name(struct_name) {
+ : m_ast_context(nullptr), m_passthrough(passthrough),
+ m_passthrough_sema(nullptr), m_sema(nullptr), m_action(nullptr),
+ m_function(function), m_struct_name(struct_name) {
if (!m_passthrough)
return;
@@ -58,7 +57,7 @@ void ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) {
if (!body_compound_stmt)
return; // do we have to handle this?
- RecordDecl *struct_decl = NULL;
+ RecordDecl *struct_decl = nullptr;
StringRef desired_name(m_struct_name);
@@ -178,8 +177,8 @@ void ASTStructExtractor::InitializeSema(Sema &S) {
}
void ASTStructExtractor::ForgetSema() {
- m_sema = NULL;
- m_action = NULL;
+ m_sema = nullptr;
+ m_action = nullptr;
if (m_passthrough_sema)
m_passthrough_sema->ForgetSema();
diff --git a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
index 65f4b00a8651..7aef2e254e1f 100644
--- a/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
+++ b/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h
@@ -1,9 +1,8 @@
//===-- ASTStructExtractor.h ------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -18,8 +17,7 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ASTStructExtractor ASTStructExtractor.h
+/// \class ASTStructExtractor ASTStructExtractor.h
/// "lldb/Expression/ASTStructExtractor.h" Extracts and describes the argument
/// structure for a wrapped function.
///
@@ -33,112 +31,85 @@ namespace lldb_private {
/// The definition of this struct is itself in the body of the wrapper
/// function, so Clang does the structure layout itself. ASTStructExtractor
/// reads through the AST for the wrapper function and finds the struct.
-//----------------------------------------------------------------------
class ASTStructExtractor : public clang::SemaConsumer {
public:
- //----------------------------------------------------------------------
/// Constructor
///
- /// @param[in] passthrough
+ /// \param[in] passthrough
/// Since the ASTs must typically go through to the Clang code generator
/// in order to produce LLVM IR, this SemaConsumer must allow them to
/// pass to the next step in the chain after processing. Passthrough is
/// the next ASTConsumer, or NULL if none is required.
///
- /// @param[in] struct_name
+ /// \param[in] struct_name
/// The name of the structure to extract from the wrapper function.
///
- /// @param[in] function
+ /// \param[in] function
/// The caller object whose members should be populated with information
/// about the argument struct. ClangFunctionCaller friends
/// ASTStructExtractor
/// for this purpose.
- //----------------------------------------------------------------------
ASTStructExtractor(clang::ASTConsumer *passthrough, const char *struct_name,
ClangFunctionCaller &function);
- //----------------------------------------------------------------------
/// Destructor
- //----------------------------------------------------------------------
~ASTStructExtractor() override;
- //----------------------------------------------------------------------
/// Link this consumer with a particular AST context
///
- /// @param[in] Context
+ /// \param[in] Context
/// This AST context will be used for types and identifiers, and also
/// forwarded to the passthrough consumer, if one exists.
- //----------------------------------------------------------------------
void Initialize(clang::ASTContext &Context) override;
- //----------------------------------------------------------------------
/// Examine a list of Decls to find the function $__lldb_expr and transform
/// its code
///
- /// @param[in] D
+ /// \param[in] D
/// The list of Decls to search. These may contain LinkageSpecDecls,
/// which need to be searched recursively. That job falls to
/// TransformTopLevelDecl.
- //----------------------------------------------------------------------
bool HandleTopLevelDecl(clang::DeclGroupRef D) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void HandleTranslationUnit(clang::ASTContext &Ctx) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void HandleTagDeclDefinition(clang::TagDecl *D) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void CompleteTentativeDefinition(clang::VarDecl *D) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void HandleVTable(clang::CXXRecordDecl *RD) override;
- //----------------------------------------------------------------------
/// Passthrough stub
- //----------------------------------------------------------------------
void PrintStats() override;
- //----------------------------------------------------------------------
/// Set the Sema object to use when performing transforms, and pass it on
///
- /// @param[in] S
+ /// \param[in] S
/// The Sema to use. Because Sema isn't externally visible, this class
/// casts it to an Action for actual use.
- //----------------------------------------------------------------------
void InitializeSema(clang::Sema &S) override;
- //----------------------------------------------------------------------
/// Reset the Sema to NULL now that transformations are done
- //----------------------------------------------------------------------
void ForgetSema() override;
private:
- //----------------------------------------------------------------------
/// Hunt the given FunctionDecl for the argument struct and place
/// information about it into m_function
///
- /// @param[in] F
+ /// \param[in] F
/// The FunctionDecl to hunt.
- //----------------------------------------------------------------------
void ExtractFromFunctionDecl(clang::FunctionDecl *F);
- //----------------------------------------------------------------------
/// Hunt the given Decl for FunctionDecls named the same as the wrapper
/// function name, recursing as necessary through LinkageSpecDecls, and
/// calling ExtractFromFunctionDecl on anything that was found
///
- /// @param[in] D
+ /// \param[in] D
/// The Decl to hunt.
- //----------------------------------------------------------------------
void ExtractFromTopLevelDecl(clang::Decl *D);
clang::ASTContext
diff --git a/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
new file mode 100644
index 000000000000..bbdf4e31c5a4
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
@@ -0,0 +1,26 @@
+//===-- ASTUtils.cpp --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTUtils.h"
+
+lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() {}
+
+void lldb_private::ExternalASTSourceWrapper::PrintStats() {
+ m_Source->PrintStats();
+}
+
+lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() {}
+
+void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); }
+
+lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() {}
+
+void lldb_private::SemaSourceWithPriorities::PrintStats() {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->PrintStats();
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/source/Plugins/ExpressionParser/Clang/ASTUtils.h
new file mode 100644
index 000000000000..d429e8c3855f
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ASTUtils.h
@@ -0,0 +1,579 @@
+//===-- ASTUtils.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 liblldb_ASTUtils_h_
+#define liblldb_ASTUtils_h_
+
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaConsumer.h"
+
+namespace lldb_private {
+
+/// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take
+/// ownership of the provided source.
+class ExternalASTSourceWrapper : public clang::ExternalSemaSource {
+ ExternalASTSource *m_Source;
+
+public:
+ ExternalASTSourceWrapper(ExternalASTSource *Source) : m_Source(Source) {
+ assert(m_Source && "Can't wrap nullptr ExternalASTSource");
+ }
+
+ ~ExternalASTSourceWrapper() override;
+
+ clang::Decl *GetExternalDecl(uint32_t ID) override {
+ return m_Source->GetExternalDecl(ID);
+ }
+
+ clang::Selector GetExternalSelector(uint32_t ID) override {
+ return m_Source->GetExternalSelector(ID);
+ }
+
+ uint32_t GetNumExternalSelectors() override {
+ return m_Source->GetNumExternalSelectors();
+ }
+
+ clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+ return m_Source->GetExternalDeclStmt(Offset);
+ }
+
+ clang::CXXCtorInitializer **
+ GetExternalCXXCtorInitializers(uint64_t Offset) override {
+ return m_Source->GetExternalCXXCtorInitializers(Offset);
+ }
+
+ clang::CXXBaseSpecifier *
+ GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+ return m_Source->GetExternalCXXBaseSpecifiers(Offset);
+ }
+
+ void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override {
+ m_Source->updateOutOfDateIdentifier(II);
+ }
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name) override {
+ return m_Source->FindExternalVisibleDeclsByName(DC, Name);
+ }
+
+ void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+ m_Source->completeVisibleDeclsMap(DC);
+ }
+
+ clang::Module *getModule(unsigned ID) override {
+ return m_Source->getModule(ID);
+ }
+
+ llvm::Optional<ASTSourceDescriptor>
+ getSourceDescriptor(unsigned ID) override {
+ return m_Source->getSourceDescriptor(ID);
+ }
+
+ ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+ return m_Source->hasExternalDefinitions(D);
+ }
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Result) override {
+ m_Source->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
+ }
+
+ void
+ FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+ m_Source->FindFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ void CompleteRedeclChain(const clang::Decl *D) override {
+ m_Source->CompleteRedeclChain(D);
+ }
+
+ void CompleteType(clang::TagDecl *Tag) override {
+ m_Source->CompleteType(Tag);
+ }
+
+ void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+ m_Source->CompleteType(Class);
+ }
+
+ void ReadComments() override { m_Source->ReadComments(); }
+
+ void StartedDeserializing() override { m_Source->StartedDeserializing(); }
+
+ void FinishedDeserializing() override { m_Source->FinishedDeserializing(); }
+
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+ m_Source->StartTranslationUnit(Consumer);
+ }
+
+ void PrintStats() 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 {
+ return m_Source->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets);
+ }
+};
+
+/// Wraps an ASTConsumer into an SemaConsumer. Doesn't take ownership of the
+/// provided consumer. If the provided ASTConsumer is also a SemaConsumer,
+/// the wrapper will also forward SemaConsumer functions.
+class ASTConsumerForwarder : public clang::SemaConsumer {
+ clang::ASTConsumer *m_c;
+ clang::SemaConsumer *m_sc;
+
+public:
+ ASTConsumerForwarder(clang::ASTConsumer *c) : m_c(c) {
+ m_sc = llvm::dyn_cast<clang::SemaConsumer>(m_c);
+ }
+
+ ~ASTConsumerForwarder() override;
+
+ void Initialize(clang::ASTContext &Context) override {
+ m_c->Initialize(Context);
+ }
+
+ bool HandleTopLevelDecl(clang::DeclGroupRef D) override {
+ return m_c->HandleTopLevelDecl(D);
+ }
+
+ void HandleInlineFunctionDefinition(clang::FunctionDecl *D) override {
+ m_c->HandleInlineFunctionDefinition(D);
+ }
+
+ void HandleInterestingDecl(clang::DeclGroupRef D) override {
+ m_c->HandleInterestingDecl(D);
+ }
+
+ void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+ m_c->HandleTranslationUnit(Ctx);
+ }
+
+ void HandleTagDeclDefinition(clang::TagDecl *D) override {
+ m_c->HandleTagDeclDefinition(D);
+ }
+
+ void HandleTagDeclRequiredDefinition(const clang::TagDecl *D) override {
+ m_c->HandleTagDeclRequiredDefinition(D);
+ }
+
+ void HandleCXXImplicitFunctionInstantiation(clang::FunctionDecl *D) override {
+ m_c->HandleCXXImplicitFunctionInstantiation(D);
+ }
+
+ void HandleTopLevelDeclInObjCContainer(clang::DeclGroupRef D) override {
+ m_c->HandleTopLevelDeclInObjCContainer(D);
+ }
+
+ void HandleImplicitImportDecl(clang::ImportDecl *D) override {
+ m_c->HandleImplicitImportDecl(D);
+ }
+
+ void CompleteTentativeDefinition(clang::VarDecl *D) override {
+ m_c->CompleteTentativeDefinition(D);
+ }
+
+ void AssignInheritanceModel(clang::CXXRecordDecl *RD) override {
+ m_c->AssignInheritanceModel(RD);
+ }
+
+ void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *D) override {
+ m_c->HandleCXXStaticMemberVarInstantiation(D);
+ }
+
+ void HandleVTable(clang::CXXRecordDecl *RD) override {
+ m_c->HandleVTable(RD);
+ }
+
+ clang::ASTMutationListener *GetASTMutationListener() override {
+ return m_c->GetASTMutationListener();
+ }
+
+ clang::ASTDeserializationListener *GetASTDeserializationListener() override {
+ return m_c->GetASTDeserializationListener();
+ }
+
+ void PrintStats() override;
+
+ void InitializeSema(clang::Sema &S) override {
+ if (m_sc)
+ m_sc->InitializeSema(S);
+ }
+
+ /// Inform the semantic consumer that Sema is no longer available.
+ void ForgetSema() override {
+ if (m_sc)
+ m_sc->ForgetSema();
+ }
+
+ bool shouldSkipFunctionBody(clang::Decl *D) override {
+ return m_c->shouldSkipFunctionBody(D);
+ }
+};
+
+/// A ExternalSemaSource multiplexer that prioritizes its sources.
+///
+/// This ExternalSemaSource will forward all requests to its attached sources.
+/// However, unlike a normal multiplexer it will not forward a request to all
+/// sources, but instead give priority to certain sources. If a source with a
+/// higher priority can fulfill a request, all sources with a lower priority
+/// will not receive the request.
+///
+/// This class is mostly use to multiplex between sources of different
+/// 'quality', e.g. a C++ modules and debug information. The C++ module will
+/// provide more accurate replies to the requests, but might not be able to
+/// answer all requests. The debug information will be used as a fallback then
+/// to provide information that is not in the C++ module.
+class SemaSourceWithPriorities : public clang::ExternalSemaSource {
+
+private:
+ /// The sources ordered in decreasing priority.
+ llvm::SmallVector<clang::ExternalSemaSource *, 2> Sources;
+
+public:
+ /// Construct a SemaSourceWithPriorities with a 'high quality' source that
+ /// has the higher priority and a 'low quality' source that will be used
+ /// as a fallback.
+ SemaSourceWithPriorities(clang::ExternalSemaSource &high_quality_source,
+ clang::ExternalSemaSource &low_quality_source) {
+ Sources.push_back(&high_quality_source);
+ Sources.push_back(&low_quality_source);
+ }
+
+ ~SemaSourceWithPriorities() override;
+
+ void addSource(clang::ExternalSemaSource &source) {
+ Sources.push_back(&source);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // ExternalASTSource.
+ //===--------------------------------------------------------------------===//
+
+ clang::Decl *GetExternalDecl(uint32_t ID) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (clang::Decl *Result = Sources[i]->GetExternalDecl(ID))
+ return Result;
+ return nullptr;
+ }
+
+ void CompleteRedeclChain(const clang::Decl *D) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteRedeclChain(D);
+ }
+
+ clang::Selector GetExternalSelector(uint32_t ID) override {
+ clang::Selector Sel;
+ for (size_t i = 0; i < Sources.size(); ++i) {
+ Sel = Sources[i]->GetExternalSelector(ID);
+ if (!Sel.isNull())
+ return Sel;
+ }
+ return Sel;
+ }
+
+ uint32_t GetNumExternalSelectors() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (uint32_t total = Sources[i]->GetNumExternalSelectors())
+ return total;
+ return 0;
+ }
+
+ clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (clang::Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
+ return Result;
+ return nullptr;
+ }
+
+ clang::CXXBaseSpecifier *
+ GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (clang::CXXBaseSpecifier *R =
+ Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
+ return R;
+ return nullptr;
+ }
+
+ clang::CXXCtorInitializer **
+ GetExternalCXXCtorInitializers(uint64_t Offset) override {
+ for (auto *S : Sources)
+ if (auto *R = S->GetExternalCXXCtorInitializers(Offset))
+ return R;
+ return nullptr;
+ }
+
+ ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+ for (const auto &S : Sources)
+ if (auto EK = S->hasExternalDefinitions(D))
+ if (EK != EK_ReplyHazy)
+ return EK;
+ return EK_ReplyHazy;
+ }
+
+ bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+ clang::DeclarationName Name) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (Sources[i]->FindExternalVisibleDeclsByName(DC, Name))
+ return true;
+ return false;
+ }
+
+ void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+ // FIXME: Only one source should be able to complete the decls map.
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->completeVisibleDeclsMap(DC);
+ }
+
+ void FindExternalLexicalDecls(
+ const clang::DeclContext *DC,
+ llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+ llvm::SmallVectorImpl<clang::Decl *> &Result) override {
+ for (size_t i = 0; i < Sources.size(); ++i) {
+ Sources[i]->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
+ if (!Result.empty())
+ return;
+ }
+ }
+
+ void
+ FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+ llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ void CompleteType(clang::TagDecl *Tag) override {
+ while (!Tag->isCompleteDefinition())
+ for (size_t i = 0; i < Sources.size(); ++i) {
+ // FIXME: We are technically supposed to loop here too until
+ // Tag->isCompleteDefinition() is true, but if our low quality source
+ // is failing to complete the tag this code will deadlock.
+ Sources[i]->CompleteType(Tag);
+ if (Tag->isCompleteDefinition())
+ break;
+ }
+ }
+
+ void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->CompleteType(Class);
+ }
+
+ void ReadComments() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadComments();
+ }
+
+ void StartedDeserializing() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartedDeserializing();
+ }
+
+ void FinishedDeserializing() override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->FinishedDeserializing();
+ }
+
+ void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->StartTranslationUnit(Consumer);
+ }
+
+ void PrintStats() override;
+
+ clang::Module *getModule(unsigned ID) override {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (auto M = Sources[i]->getModule(ID))
+ return M;
+ return nullptr;
+ }
+
+ bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override {
+ for (auto *S : Sources)
+ if (S->DeclIsFromPCHWithObjectFile(D))
+ return true;
+ return false;
+ }
+
+ 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 {
+ for (size_t i = 0; i < Sources.size(); ++i)
+ if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+ BaseOffsets, VirtualBaseOffsets))
+ return true;
+ return false;
+ }
+
+ void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
+ for (auto &Source : Sources)
+ Source->getMemoryBufferSizes(sizes);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // ExternalSemaSource.
+ //===--------------------------------------------------------------------===//
+
+ void InitializeSema(clang::Sema &S) override {
+ for (auto &Source : Sources)
+ Source->InitializeSema(S);
+ }
+
+ void ForgetSema() override {
+ for (auto &Source : Sources)
+ Source->ForgetSema();
+ }
+
+ void ReadMethodPool(clang::Selector Sel) override {
+ for (auto &Source : Sources)
+ Source->ReadMethodPool(Sel);
+ }
+
+ void updateOutOfDateSelector(clang::Selector Sel) override {
+ for (auto &Source : Sources)
+ Source->updateOutOfDateSelector(Sel);
+ }
+
+ void ReadKnownNamespaces(
+ llvm::SmallVectorImpl<clang::NamespaceDecl *> &Namespaces) override {
+ for (auto &Source : Sources)
+ Source->ReadKnownNamespaces(Namespaces);
+ }
+
+ void ReadUndefinedButUsed(
+ llvm::MapVector<clang::NamedDecl *, clang::SourceLocation> &Undefined)
+ override {
+ for (auto &Source : Sources)
+ Source->ReadUndefinedButUsed(Undefined);
+ }
+
+ void ReadMismatchingDeleteExpressions(
+ llvm::MapVector<clang::FieldDecl *,
+ llvm::SmallVector<std::pair<clang::SourceLocation, bool>,
+ 4>> &Exprs) override {
+ for (auto &Source : Sources)
+ Source->ReadMismatchingDeleteExpressions(Exprs);
+ }
+
+ bool LookupUnqualified(clang::LookupResult &R, clang::Scope *S) override {
+ for (auto &Source : Sources) {
+ Source->LookupUnqualified(R, S);
+ if (!R.empty())
+ break;
+ }
+
+ return !R.empty();
+ }
+
+ void ReadTentativeDefinitions(
+ llvm::SmallVectorImpl<clang::VarDecl *> &Defs) override {
+ for (auto &Source : Sources)
+ Source->ReadTentativeDefinitions(Defs);
+ }
+
+ void ReadUnusedFileScopedDecls(
+ llvm::SmallVectorImpl<const clang::DeclaratorDecl *> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadUnusedFileScopedDecls(Decls);
+ }
+
+ void ReadDelegatingConstructors(
+ llvm::SmallVectorImpl<clang::CXXConstructorDecl *> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadDelegatingConstructors(Decls);
+ }
+
+ void ReadExtVectorDecls(
+ llvm::SmallVectorImpl<clang::TypedefNameDecl *> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadExtVectorDecls(Decls);
+ }
+
+ void ReadUnusedLocalTypedefNameCandidates(
+ llvm::SmallSetVector<const clang::TypedefNameDecl *, 4> &Decls) override {
+ for (auto &Source : Sources)
+ Source->ReadUnusedLocalTypedefNameCandidates(Decls);
+ }
+
+ void ReadReferencedSelectors(
+ llvm::SmallVectorImpl<std::pair<clang::Selector, clang::SourceLocation>>
+ &Sels) override {
+ for (auto &Source : Sources)
+ Source->ReadReferencedSelectors(Sels);
+ }
+
+ void ReadWeakUndeclaredIdentifiers(
+ llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *, clang::WeakInfo>>
+ &WI) override {
+ for (auto &Source : Sources)
+ Source->ReadWeakUndeclaredIdentifiers(WI);
+ }
+
+ void ReadUsedVTables(
+ llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override {
+ for (auto &Source : Sources)
+ Source->ReadUsedVTables(VTables);
+ }
+
+ void ReadPendingInstantiations(
+ llvm::SmallVectorImpl<
+ std::pair<clang::ValueDecl *, clang::SourceLocation>> &Pending)
+ override {
+ for (auto &Source : Sources)
+ Source->ReadPendingInstantiations(Pending);
+ }
+
+ void ReadLateParsedTemplates(
+ llvm::MapVector<const clang::FunctionDecl *,
+ std::unique_ptr<clang::LateParsedTemplate>> &LPTMap)
+ override {
+ for (auto &Source : Sources)
+ Source->ReadLateParsedTemplates(LPTMap);
+ }
+
+ clang::TypoCorrection
+ CorrectTypo(const clang::DeclarationNameInfo &Typo, int LookupKind,
+ clang::Scope *S, clang::CXXScopeSpec *SS,
+ clang::CorrectionCandidateCallback &CCC,
+ clang::DeclContext *MemberContext, bool EnteringContext,
+ const clang::ObjCObjectPointerType *OPT) override {
+ for (auto &Source : Sources) {
+ if (clang::TypoCorrection C =
+ Source->CorrectTypo(Typo, LookupKind, S, SS, CCC,
+ MemberContext, EnteringContext, OPT))
+ return C;
+ }
+ return clang::TypoCorrection();
+ }
+
+ bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
+ clang::QualType T) override {
+ for (auto &Source : Sources) {
+ if (Source->MaybeDiagnoseMissingCompleteType(Loc, T))
+ return true;
+ }
+ return false;
+ }
+};
+
+} // namespace lldb_private
+#endif // liblldb_ASTUtils_h_
diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 84771e59531d..c5778f86bb62 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -1,9 +1,8 @@
//===-- ClangASTSource.cpp ---------------------------------------*- C++-*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -21,21 +20,21 @@
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/TaggedASTType.h"
-#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+#include <memory>
#include <vector>
using namespace clang;
using namespace lldb_private;
-//------------------------------------------------------------------
// Scoped class that will remove an active lexical decl from the set when it
// goes out of scope.
-//------------------------------------------------------------------
namespace {
class ScopedLexicalDeclEraser {
public:
@@ -53,7 +52,7 @@ private:
ClangASTSource::ClangASTSource(const lldb::TargetSP &target)
: m_import_in_progress(false), m_lookups_enabled(false), m_target(target),
- m_ast_context(NULL), m_active_lexical_decls(), m_active_lookups() {
+ m_ast_context(nullptr), m_active_lexical_decls(), m_active_lookups() {
if (!target->GetUseModernTypeLookup()) {
m_ast_importer_sp = m_target->GetClangASTImporter();
}
@@ -92,7 +91,7 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context,
if (!process)
break;
- ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
if (!language_runtime)
break;
@@ -103,7 +102,7 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context,
break;
sources.push_back(runtime_decl_vendor->GetImporterSource());
- } while (0);
+ } while (false);
do {
DeclVendor *modules_decl_vendor =
@@ -113,7 +112,7 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context,
break;
sources.push_back(modules_decl_vendor->GetImporterSource());
- } while (0);
+ } while (false);
if (!is_shared_context) {
// Update the scratch AST context's merger to reflect any new sources we
@@ -127,7 +126,9 @@ void ClangASTSource::InstallASTContext(clang::ASTContext &ast_context,
sources.push_back({*scratch_ast_context->getASTContext(),
*scratch_ast_context->getFileManager(),
scratch_ast_context->GetOriginMap()});
- } while (0);
+ }
+ while (false)
+ ;
m_merger_up =
llvm::make_unique<clang::ExternalASTMerger>(target, sources);
@@ -443,8 +444,8 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) {
return;
}
- Decl *original_decl = NULL;
- ASTContext *original_ctx = NULL;
+ Decl *original_decl = nullptr;
+ ASTContext *original_ctx = nullptr;
if (m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl,
&original_ctx)) {
@@ -477,12 +478,12 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
lldb::ProcessSP process(m_target->GetProcessSP());
if (!process)
- return NULL;
+ return nullptr;
- ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
if (!language_runtime)
- return NULL;
+ return nullptr;
ConstString class_name(interface_decl->getNameAsString().c_str());
@@ -490,7 +491,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
language_runtime->LookupInCompleteClassCache(class_name));
if (!complete_type_sp)
- return NULL;
+ return nullptr;
TypeFromUser complete_type =
TypeFromUser(complete_type_sp->GetFullCompilerType());
@@ -498,7 +499,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
complete_type.GetOpaqueQualType();
if (!complete_opaque_type)
- return NULL;
+ return nullptr;
const clang::Type *complete_clang_type =
QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr();
@@ -506,7 +507,7 @@ clang::ObjCInterfaceDecl *ClangASTSource::GetCompleteObjCInterface(
dyn_cast<ObjCInterfaceType>(complete_clang_type);
if (!complete_interface_type)
- return NULL;
+ return nullptr;
ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl());
@@ -571,8 +572,8 @@ void ClangASTSource::FindExternalLexicalDecls(
current_id, static_cast<const void *>(m_ast_context));
}
- Decl *original_decl = NULL;
- ASTContext *original_ctx = NULL;
+ Decl *original_decl = nullptr;
+ ASTContext *original_ctx = nullptr;
if (!m_ast_importer_sp->ResolveDeclOrigin(context_decl, &original_decl,
&original_ctx))
@@ -611,10 +612,15 @@ void ClangASTSource::FindExternalLexicalDecls(
if (!original_decl_context)
return;
+ // 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;
+ // The predicate function returns true if the passed declaration kind is
+ // the one we are looking for.
+ // See clang::ExternalASTSource::FindExternalLexicalDecls()
if (predicate(decl->getKind())) {
if (log) {
ASTDumper ast_dumper(decl);
@@ -639,21 +645,22 @@ void ClangASTSource::FindExternalLexicalDecls(
m_ast_importer_sp->RequireCompleteType(copied_field_type);
}
-
- DeclContext *decl_context_non_const =
- const_cast<DeclContext *>(decl_context);
-
- if (copied_decl->getDeclContext() != decl_context) {
- if (copied_decl->getDeclContext()->containsDecl(copied_decl))
- copied_decl->getDeclContext()->removeDecl(copied_decl);
- copied_decl->setDeclContext(decl_context_non_const);
- }
-
- if (!decl_context_non_const->containsDecl(copied_decl))
- decl_context_non_const->addDeclInternal(copied_decl);
+ } else {
+ SkippedDecls = true;
}
}
+ // CopyDecl may build a lookup table which may set up ExternalLexicalStorage
+ // to false. However, since we skipped some of the external Decls we must
+ // set it back!
+ if (SkippedDecls) {
+ decl_context->setHasExternalLexicalStorage(true);
+ // This sets HasLazyExternalLexicalLookups to true. By setting this bit we
+ // ensure that the lookup table is rebuilt, which means the external source
+ // is consulted again when a clang::DeclContext::lookup is called.
+ const_cast<DeclContext *>(decl_context)->setMustBuildLookupTable();
+ }
+
return;
}
@@ -708,7 +715,7 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) {
return; // otherwise we may need to fall back
}
- context.m_namespace_map.reset(new ClangASTImporter::NamespaceMap);
+ context.m_namespace_map = std::make_shared<ClangASTImporter::NamespaceMap>();
if (const NamespaceDecl *namespace_context =
dyn_cast<NamespaceDecl>(context.m_decl_context)) {
@@ -763,6 +770,10 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) {
}
}
+clang::Sema *ClangASTSource::getSema() {
+ return ClangASTContext::GetASTContext(m_ast_context)->getSema();
+}
+
bool ClangASTSource::IgnoreName(const ConstString name,
bool ignore_all_dollar_names) {
static const ConstString id_name("id");
@@ -932,7 +943,7 @@ void ClangASTSource::FindExternalVisibleDecls(
context.m_found.type = true;
}
}
- } while (0);
+ } while (false);
}
if (!context.m_found.type) {
@@ -946,7 +957,7 @@ void ClangASTSource::FindExternalVisibleDecls(
break;
ObjCLanguageRuntime *language_runtime(
- process->GetObjCLanguageRuntime());
+ ObjCLanguageRuntime::Get(*process));
if (!language_runtime)
break;
@@ -983,17 +994,17 @@ void ClangASTSource::FindExternalVisibleDecls(
}
context.AddNamedDecl(copied_named_decl);
- } while (0);
+ } while (false);
}
- } while (0);
+ } while (false);
}
template <class D> class TaggedASTDecl {
public:
- TaggedASTDecl() : decl(NULL) {}
+ TaggedASTDecl() : decl(nullptr) {}
TaggedASTDecl(D *_decl) : decl(_decl) {}
- bool IsValid() const { return (decl != NULL); }
+ bool IsValid() const { return (decl != nullptr); }
bool IsInvalid() const { return !IsValid(); }
D *operator->() const { return decl; }
D *decl;
@@ -1026,7 +1037,7 @@ public:
template <class D>
DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTSource &source) {
DeclFromUser<> origin_decl;
- source.ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
+ source.ResolveDeclOrigin(this->decl, &origin_decl.decl, nullptr);
if (origin_decl.IsInvalid())
return DeclFromUser<D>();
return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
@@ -1156,8 +1167,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
return;
do {
- Decl *original_decl = NULL;
- ASTContext *original_ctx = NULL;
+ Decl *original_decl = nullptr;
+ ASTContext *original_ctx = nullptr;
m_ast_importer_sp->ResolveDeclOrigin(interface_decl, &original_decl,
&original_ctx);
@@ -1171,7 +1182,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
if (FindObjCMethodDeclsWithOrigin(current_id, context,
original_interface_decl, "at origin"))
return; // found it, no need to look any further
- } while (0);
+ } while (false);
StreamString ss;
@@ -1276,7 +1287,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
if (*cursor == ' ' || *cursor == '(')
sc_list.Append(candidate_sc);
}
- } while (0);
+ } while (false);
if (sc_list.GetSize()) {
// We found a good function symbol. Use that.
@@ -1359,7 +1370,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
"in debug info");
return;
- } while (0);
+ } while (false);
do {
// Check the modules only if the debug information didn't have a complete
@@ -1386,7 +1397,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
current_id, context, interface_decl_from_modules, "in modules"))
return;
}
- } while (0);
+ } while (false);
do {
// Check the runtime only if the debug information didn't have a complete
@@ -1397,7 +1408,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
if (!process)
break;
- ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
if (!language_runtime)
break;
@@ -1423,7 +1434,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) {
FindObjCMethodDeclsWithOrigin(current_id, context, runtime_interface_decl,
"in runtime");
- } while (0);
+ } while (false);
}
static bool FindObjCPropertyAndIvarDeclsWithOrigin(
@@ -1542,7 +1553,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) {
complete_iface_decl);
return;
- } while (0);
+ } while (false);
do {
// Check the modules only if the debug information didn't have a complete
@@ -1578,7 +1589,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) {
if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id, context, *this,
interface_decl_from_modules))
return;
- } while (0);
+ } while (false);
do {
// Check the runtime only if the debug information didn't have a complete
@@ -1589,7 +1600,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) {
if (!process)
return;
- ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+ ObjCLanguageRuntime *language_runtime(ObjCLanguageRuntime::Get(*process));
if (!language_runtime)
return;
@@ -1623,7 +1634,7 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) {
if (FindObjCPropertyAndIvarDeclsWithOrigin(
current_id, context, *this, interface_decl_from_runtime))
return;
- } while (0);
+ } while (false);
}
typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap;
@@ -1836,7 +1847,7 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size,
}
void ClangASTSource::CompleteNamespaceMap(
- ClangASTImporter::NamespaceMapSP &namespace_map, const ConstString &name,
+ ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name,
ClangASTImporter::NamespaceMapSP &parent_map) const {
static unsigned int invocation_id = 0;
unsigned int current_id = invocation_id++;
@@ -1966,7 +1977,14 @@ clang::QualType ClangASTSource::CopyTypeWithMerger(
return QualType();
}
- return merger.ImporterForOrigin(from_context).Import(type);
+ if (llvm::Expected<QualType> type_or_error =
+ merger.ImporterForOrigin(from_context).Import(type)) {
+ return *type_or_error;
+ } else {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ LLDB_LOG_ERROR(log, type_or_error.takeError(), "Couldn't import type: {0}");
+ return QualType();
+ }
}
clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) {
@@ -1979,7 +1997,16 @@ clang::Decl *ClangASTSource::CopyDecl(Decl *src_decl) {
return nullptr;
}
- return m_merger_up->ImporterForOrigin(from_context).Import(src_decl);
+ if (llvm::Expected<Decl *> decl_or_error =
+ m_merger_up->ImporterForOrigin(from_context).Import(src_decl)) {
+ return *decl_or_error;
+ } else {
+ Log *log =
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ LLDB_LOG_ERROR(log, decl_or_error.takeError(),
+ "Couldn't import decl: {0}");
+ return nullptr;
+ }
} else {
lldbassert(0 && "No mechanism for copying a decl!");
return nullptr;
@@ -2045,12 +2072,12 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) {
assert(type && "Type for variable must be valid!");
if (!type.IsValid())
- return NULL;
+ return nullptr;
ClangASTContext *lldb_ast =
llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem());
if (!lldb_ast)
- return NULL;
+ return nullptr;
IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
@@ -2058,7 +2085,7 @@ clang::NamedDecl *NameSearchContext::AddVarDecl(const CompilerType &type) {
clang::NamedDecl *Decl = VarDecl::Create(
*ast, const_cast<DeclContext *>(m_decl_context), SourceLocation(),
- SourceLocation(), ii, ClangUtil::GetQualType(type), 0, SC_Static);
+ SourceLocation(), ii, ClangUtil::GetQualType(type), nullptr, SC_Static);
m_decls.push_back(Decl);
return Decl;
@@ -2069,15 +2096,15 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
assert(type && "Type for variable must be valid!");
if (!type.IsValid())
- return NULL;
+ return nullptr;
if (m_function_types.count(type))
- return NULL;
+ return nullptr;
ClangASTContext *lldb_ast =
llvm::dyn_cast<ClangASTContext>(type.GetTypeSystem());
if (!lldb_ast)
- return NULL;
+ return nullptr;
m_function_types.insert(type);
@@ -2106,8 +2133,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
clang::FunctionDecl *func_decl = FunctionDecl::Create(
*ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type,
- NULL, SC_Extern, isInlineSpecified, hasWrittenPrototype,
- isConstexprSpecified);
+ 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
@@ -2125,9 +2152,10 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
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(), NULL, arg_qual_type, NULL, SC_Static, NULL));
+ 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));
@@ -2148,7 +2176,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type,
ClangASTContext::IsOperator(decl_name.getAsString().c_str(), op_kind)) {
if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount(
false, op_kind, func_proto_type->getNumParams()))
- return NULL;
+ return nullptr;
}
m_decls.push_back(func_decl);
@@ -2196,7 +2224,7 @@ NameSearchContext::AddTypeDecl(const CompilerType &clang_type) {
return (NamedDecl *)interface_decl;
}
}
- return NULL;
+ return nullptr;
}
void NameSearchContext::AddLookupResult(clang::DeclContextLookupResult result) {
diff --git a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
index a42422b0f97f..7a8bacf48a8f 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
@@ -1,9 +1,8 @@
//===-- ClangASTSource.h ----------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -23,8 +22,7 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+/// \class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h"
/// Provider for named objects defined in the debug info for Clang
///
/// As Clang parses an expression, it may encounter names that are not defined
@@ -32,37 +30,30 @@ namespace lldb_private {
/// knows the name it is looking for, but nothing else. The ExternalSemaSource
/// class provides Decls (VarDecl, FunDecl, TypeDecl) to Clang for these
/// names, consulting the ClangExpressionDeclMap to do the actual lookups.
-//----------------------------------------------------------------------
class ClangASTSource : public ClangExternalASTSourceCommon,
public ClangASTImporter::MapCompleter {
public:
- //------------------------------------------------------------------
/// Constructor
///
/// Initializes class variables.
///
- /// @param[in] target
+ /// \param[in] target
/// A reference to the target containing debug information to use.
- //------------------------------------------------------------------
ClangASTSource(const lldb::TargetSP &target);
- //------------------------------------------------------------------
/// Destructor
- //------------------------------------------------------------------
~ClangASTSource() override;
- //------------------------------------------------------------------
/// Interface stubs.
- //------------------------------------------------------------------
- clang::Decl *GetExternalDecl(uint32_t) override { return NULL; }
- clang::Stmt *GetExternalDeclStmt(uint64_t) override { return NULL; }
+ clang::Decl *GetExternalDecl(uint32_t) override { return nullptr; }
+ clang::Stmt *GetExternalDeclStmt(uint64_t) override { return nullptr; }
clang::Selector GetExternalSelector(uint32_t) override {
return clang::Selector();
}
uint32_t GetNumExternalSelectors() override { return 0; }
clang::CXXBaseSpecifier *
GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
- return NULL;
+ return nullptr;
}
void MaterializeVisibleDecls(const clang::DeclContext *DC) { return; }
@@ -74,7 +65,6 @@ public:
// APIs for ExternalASTSource
//
- //------------------------------------------------------------------
/// Look up all Decls that match a particular name. Only handles
/// Identifiers and DeclContexts that are either NamespaceDecls or
/// TranslationUnitDecls. Calls SetExternalVisibleDeclsForName with the
@@ -83,69 +73,64 @@ public:
/// The work for this function is done by
/// void FindExternalVisibleDecls (NameSearchContext &);
///
- /// @param[in] DC
+ /// \param[in] DC
/// The DeclContext to register the found Decls in.
///
- /// @param[in] Name
+ /// \param[in] Name
/// The name to find entries for.
///
- /// @return
+ /// \return
/// Whatever SetExternalVisibleDeclsForName returns.
- //------------------------------------------------------------------
bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
clang::DeclarationName Name) override;
- //------------------------------------------------------------------
/// Enumerate all Decls in a given lexical context.
///
- /// @param[in] DC
+ /// \param[in] DC
/// The DeclContext being searched.
///
- /// @param[in] isKindWeWant
+ /// \param[in] isKindWeWant
/// A callback function that returns true given the
/// DeclKinds of desired Decls, and false otherwise.
///
- /// @param[in] Decls
+ /// \param[in] Decls
/// A vector that is filled in with matching Decls.
- //------------------------------------------------------------------
void FindExternalLexicalDecls(
const clang::DeclContext *DC,
llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
llvm::SmallVectorImpl<clang::Decl *> &Decls) override;
- //------------------------------------------------------------------
/// Specify the layout of the contents of a RecordDecl.
///
- /// @param[in] Record
+ /// \param[in] Record
/// The record (in the parser's AST context) that needs to be
/// laid out.
///
- /// @param[out] Size
+ /// \param[out] Size
/// The total size of the record in bits.
///
- /// @param[out] Alignment
+ /// \param[out] Alignment
/// The alignment of the record in bits.
///
- /// @param[in] FieldOffsets
+ /// \param[in] FieldOffsets
/// A map that must be populated with pairs of the record's
/// fields (in the parser's AST context) and their offsets
/// (measured in bits).
///
- /// @param[in] BaseOffsets
+ /// \param[in] BaseOffsets
/// A map that must be populated with pairs of the record's
/// C++ concrete base classes (in the parser's AST context,
/// and only if the record is a CXXRecordDecl and has base
/// classes) and their offsets (measured in bytes).
///
- /// @param[in] VirtualBaseOffsets
+ /// \param[in] VirtualBaseOffsets
/// A map that must be populated with pairs of the record's
/// C++ virtual base classes (in the parser's AST context,
/// and only if the record is a CXXRecordDecl and has base
/// classes) and their offsets (measured in bytes).
///
- /// @return
+ /// \return
/// True <=> the layout is valid.
- //-----------------------------------------------------------------
bool layoutRecordType(
const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
@@ -154,52 +139,44 @@ public:
llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
&VirtualBaseOffsets) override;
- //------------------------------------------------------------------
/// Complete a TagDecl.
///
- /// @param[in] Tag
+ /// \param[in] Tag
/// The Decl to be completed in place.
- //------------------------------------------------------------------
void CompleteType(clang::TagDecl *Tag) override;
- //------------------------------------------------------------------
/// Complete an ObjCInterfaceDecl.
///
- /// @param[in] Class
+ /// \param[in] Class
/// The Decl to be completed in place.
- //------------------------------------------------------------------
void CompleteType(clang::ObjCInterfaceDecl *Class) override;
- //------------------------------------------------------------------
/// Called on entering a translation unit. Tells Clang by calling
/// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() that
/// this object has something to say about undefined names.
///
- /// @param[in] ASTConsumer
+ /// \param[in] ASTConsumer
/// Unused.
- //------------------------------------------------------------------
void StartTranslationUnit(clang::ASTConsumer *Consumer) override;
//
// APIs for NamespaceMapCompleter
//
- //------------------------------------------------------------------
/// Look up the modules containing a given namespace and put the appropriate
/// entries in the namespace map.
///
- /// @param[in] namespace_map
+ /// \param[in] namespace_map
/// The map to be completed.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the namespace to be found.
///
- /// @param[in] parent_map
+ /// \param[in] parent_map
/// The map for the namespace's parent namespace, if there is
/// one.
- //------------------------------------------------------------------
void CompleteNamespaceMap(
- ClangASTImporter::NamespaceMapSP &namespace_map, const ConstString &name,
+ ClangASTImporter::NamespaceMapSP &namespace_map, ConstString name,
ClangASTImporter::NamespaceMapSP &parent_map) const override;
//
@@ -210,14 +187,14 @@ public:
AddNamespace(NameSearchContext &context,
ClangASTImporter::NamespaceMapSP &namespace_decls);
- //------------------------------------------------------------------
/// The worker function for FindExternalVisibleDeclsByName.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when filing results.
- //------------------------------------------------------------------
virtual void FindExternalVisibleDecls(NameSearchContext &context);
+ clang::Sema *getSema();
+
void SetImportInProgress(bool import_in_progress) {
m_import_in_progress = import_in_progress;
}
@@ -228,13 +205,11 @@ public:
}
bool GetLookupsEnabled() { return m_lookups_enabled; }
- //----------------------------------------------------------------------
- /// @class ClangASTSourceProxy ClangASTSource.h
+ /// \class ClangASTSourceProxy ClangASTSource.h
/// "lldb/Expression/ClangASTSource.h" Proxy for ClangASTSource
///
/// Clang AST contexts like to own their AST sources, so this is a state-
/// free proxy object.
- //----------------------------------------------------------------------
class ClangASTSourceProxy : public ClangExternalASTSourceCommon {
public:
ClangASTSourceProxy(ClangASTSource &original) : m_original(original) {}
@@ -295,157 +270,135 @@ public:
}
protected:
- //------------------------------------------------------------------
/// Look for the complete version of an Objective-C interface, and return it
/// if found.
///
- /// @param[in] interface_decl
+ /// \param[in] interface_decl
/// An ObjCInterfaceDecl that may not be the complete one.
///
- /// @return
+ /// \return
/// NULL if the complete interface couldn't be found;
/// the complete interface otherwise.
- //------------------------------------------------------------------
clang::ObjCInterfaceDecl *
GetCompleteObjCInterface(const clang::ObjCInterfaceDecl *interface_decl);
- //------------------------------------------------------------------
/// Find all entities matching a given name in a given module, using a
/// NameSearchContext to make Decls for them.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext that can construct Decls for this name.
///
- /// @param[in] module
+ /// \param[in] module
/// If non-NULL, the module to query.
///
- /// @param[in] namespace_decl
+ /// \param[in] namespace_decl
/// If valid and module is non-NULL, the parent namespace.
///
- /// @param[in] current_id
+ /// \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);
- //------------------------------------------------------------------
/// Find all Objective-C methods matching a given selector.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext that can construct Decls for this name.
/// Its m_decl_name contains the selector and its m_decl_context
/// is the containing object.
- //------------------------------------------------------------------
void FindObjCMethodDecls(NameSearchContext &context);
- //------------------------------------------------------------------
/// Find all Objective-C properties and ivars with a given name.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext that can construct Decls for this name.
/// Its m_decl_name contains the name and its m_decl_context
/// is the containing object.
- //------------------------------------------------------------------
void FindObjCPropertyAndIvarDecls(NameSearchContext &context);
- //------------------------------------------------------------------
/// A wrapper for ClangASTContext::CopyType that sets a flag that
/// indicates that we should not respond to queries during import.
///
- /// @param[in] dest_context
+ /// \param[in] dest_context
/// The target AST context, typically the parser's AST context.
///
- /// @param[in] source_context
+ /// \param[in] source_context
/// The source AST context, typically the AST context of whatever
/// symbol file the type was found in.
///
- /// @param[in] src_type
+ /// \param[in] src_type
/// The source type.
///
- /// @return
+ /// \return
/// The imported type.
- //------------------------------------------------------------------
CompilerType GuardedCopyType(const CompilerType &src_type);
public:
- //------------------------------------------------------------------
/// Returns true if a name should be ignored by name lookup.
///
- /// @param[in] name
+ /// \param[in] name
/// The name to be considered.
///
- /// @param[in] ignore_all_dollar_nmmes
+ /// \param[in] ignore_all_dollar_nmmes
/// True if $-names of all sorts should be ignored.
///
- /// @return
+ /// \return
/// True if the name is one of a class of names that are ignored by
/// 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
+ /// \param[in] src_decl
/// The Decl to copy.
///
- /// @return
+ /// \return
/// A copy of the Decl in m_ast_context, or NULL if the copy failed.
- //------------------------------------------------------------------
clang::Decl *CopyDecl(clang::Decl *src_decl);
- //------------------------------------------------------------------
/// Copies a single Type to the target of the given ExternalASTMerger.
///
- /// @param[in] src_context
+ /// \param[in] src_context
/// The ASTContext containing the type.
///
- /// @param[in] merger
+ /// \param[in] merger
/// The merger to use. This isn't just *m_merger_up because it might be
/// the persistent AST context's merger.
///
- /// @param[in] type
+ /// \param[in] type
/// The type to copy.
///
- /// @return
+ /// \return
/// A copy of the Type in the merger's target context.
- //------------------------------------------------------------------
clang::QualType CopyTypeWithMerger(clang::ASTContext &src_context,
clang::ExternalASTMerger &merger,
clang::QualType type);
- //------------------------------------------------------------------
/// Determined the origin of a single Decl, if it can be found.
///
- /// @param[in] decl
+ /// \param[in] decl
/// The Decl whose origin is to be found.
///
- /// @param[out] original_decl
+ /// \param[out] original_decl
/// A pointer whose target is filled in with the original Decl.
///
- /// @param[in] original_ctx
+ /// \param[in] original_ctx
/// A pointer whose target is filled in with the original's ASTContext.
///
- /// @return
+ /// \return
/// True if lookup succeeded; false otherwise.
- //------------------------------------------------------------------
bool ResolveDeclOrigin(const clang::Decl *decl, clang::Decl **original_decl,
clang::ASTContext **original_ctx);
- //------------------------------------------------------------------
/// Returns m_merger_up. Only call this if the target is configured to use
/// modern lookup,
- //------------------------------------------------------------------
clang::ExternalASTMerger &GetMergerUnchecked();
- //------------------------------------------------------------------
/// Returns true if there is a merger. This only occurs if the target is
/// using modern lookup.
- //------------------------------------------------------------------
bool HasMerger() { return (bool)m_merger_up; }
protected:
@@ -471,15 +424,13 @@ protected:
std::set<const char *> m_active_lookups;
};
-//----------------------------------------------------------------------
-/// @class NameSearchContext ClangASTSource.h
+/// \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 {
ClangASTSource &m_ast_source; ///< The AST source making the request
llvm::SmallVectorImpl<clang::NamedDecl *>
@@ -504,24 +455,22 @@ struct NameSearchContext {
bool type : 1;
} m_found;
- //------------------------------------------------------------------
/// Constructor
///
/// Initializes class variables.
///
- /// @param[in] astSource
+ /// \param[in] astSource
/// A reference to the AST source making a request.
///
- /// @param[in] decls
+ /// \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
+ /// \param[in] name
/// The name being searched for (always an Identifier).
///
- /// @param[in] dc
+ /// \param[in] dc
/// The DeclContext to register Decls in.
- //------------------------------------------------------------------
NameSearchContext(ClangASTSource &astSource,
llvm::SmallVectorImpl<clang::NamedDecl *> &decls,
clang::DeclarationName &name, const clang::DeclContext *dc)
@@ -530,59 +479,47 @@ struct NameSearchContext {
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
+ /// \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
+ /// \param[in] type
/// The opaque QualType for the FunDecl being registered.
///
- /// @param[in] extern_c
+ /// \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
+ /// \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
+ /// \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
+ /// \param[in] decl
/// The NamedDecl, usually returned as the result
/// of querying a DeclContext.
- //------------------------------------------------------------------
void AddNamedDecl(clang::NamedDecl *decl);
};
diff --git a/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
index 9ea4e3aa7dab..db50c2aa3e90 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
@@ -1,9 +1,8 @@
//===-- ClangDiagnostic.h ---------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -34,7 +33,7 @@ public:
uint32_t compiler_id)
: Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id) {}
- virtual ~ClangDiagnostic() = default;
+ ~ClangDiagnostic() override = default;
bool HasFixIts() const override { return !m_fixit_vec.empty(); }
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 9c2f8c4b6c92..a49a7029e0d2 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1,9 +1,8 @@
//===-- ClangExpressionDeclMap.cpp -----------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -33,9 +32,7 @@
#include "lldb/Symbol/TypeList.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
-#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StackFrame.h"
@@ -54,6 +51,8 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
using namespace lldb;
using namespace lldb_private;
@@ -66,10 +65,11 @@ const char *g_lldb_local_vars_namespace_cstr = "$__lldb_local_vars";
ClangExpressionDeclMap::ClangExpressionDeclMap(
bool keep_result_in_memory,
Materializer::PersistentVariableDelegate *result_delegate,
- ExecutionContext &exe_ctx)
+ ExecutionContext &exe_ctx, ValueObject *ctx_obj)
: ClangASTSource(exe_ctx.GetTargetSP()), m_found_entities(),
m_struct_members(), m_keep_result_in_memory(keep_result_in_memory),
- m_result_delegate(result_delegate), m_parser_vars(), m_struct_vars() {
+ m_result_delegate(result_delegate), m_ctx_obj(ctx_obj), m_parser_vars(),
+ m_struct_vars() {
EnableStructVars();
}
@@ -132,7 +132,7 @@ void ClangExpressionDeclMap::DidParse() {
if (log)
ClangASTMetrics::DumpCounters(log);
- if (m_parser_vars.get()) {
+ if (m_parser_vars) {
for (size_t entity_index = 0, num_entities = m_found_entities.GetSize();
entity_index < num_entities; ++entity_index) {
ExpressionVariableSP var_sp(
@@ -272,9 +272,15 @@ static clang::QualType ExportAllDeclaredTypes(
merger.AddSources(importer_source);
clang::ASTImporter &exporter = merger.ImporterForOrigin(source);
CompleteAllDeclContexts(exporter, file, root);
- clang::QualType ret = exporter.Import(root);
+ llvm::Expected<clang::QualType> ret_or_error = exporter.Import(root);
merger.RemoveSources(importer_source);
- return ret;
+ if (ret_or_error) {
+ return *ret_or_error;
+ } else {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ LLDB_LOG_ERROR(log, ret_or_error.takeError(), "Couldn't import type: {0}");
+ return clang::QualType();
+ }
}
TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target,
@@ -309,7 +315,7 @@ TypeFromUser ClangExpressionDeclMap::DeportType(ClangASTContext &target,
}
bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl,
- const ConstString &name,
+ ConstString name,
TypeFromParser parser_type,
bool is_result,
bool is_lvalue) {
@@ -361,7 +367,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl,
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
Target *target = exe_ctx.GetTargetPtr();
- if (target == NULL)
+ if (target == nullptr)
return false;
ClangASTContext *context(target->GetScratchClangASTContext());
@@ -424,7 +430,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl,
}
bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl,
- const ConstString &name,
+ ConstString name,
llvm::Value *value, size_t size,
lldb::offset_t alignment) {
assert(m_struct_vars.get());
@@ -604,7 +610,7 @@ bool ClangExpressionDeclMap::GetFunctionInfo(const NamedDecl *decl,
addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target,
Process *process,
- const ConstString &name,
+ ConstString name,
lldb::SymbolType symbol_type,
lldb_private::Module *module) {
SymbolContextList sc_list;
@@ -692,7 +698,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target,
}
if (symbol_load_addr == LLDB_INVALID_ADDRESS && process) {
- ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime();
+ ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process);
if (runtime) {
symbol_load_addr = runtime->LookupRuntimeSymbol(name);
@@ -702,7 +708,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(Target &target,
return symbol_load_addr;
}
-addr_t ClangExpressionDeclMap::GetSymbolAddress(const ConstString &name,
+addr_t ClangExpressionDeclMap::GetSymbolAddress(ConstString name,
lldb::SymbolType symbol_type) {
assert(m_parser_vars.get());
@@ -715,7 +721,7 @@ addr_t ClangExpressionDeclMap::GetSymbolAddress(const ConstString &name,
}
lldb::VariableSP ClangExpressionDeclMap::FindGlobalVariable(
- Target &target, ModuleSP &module, const ConstString &name,
+ Target &target, ModuleSP &module, ConstString name,
CompilerDeclContext *namespace_decl, TypeFromUser *type) {
VariableList vars;
@@ -921,16 +927,31 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
name.GetCString());
context.AddNamedDecl(parser_named_decl);
- } while (0);
+ } while (false);
}
if (name.GetCString()[0] == '$' && !namespace_decl) {
static ConstString g_lldb_class_name("$__lldb_class");
if (name == g_lldb_class_name) {
+ if (m_ctx_obj) {
+ Status status;
+ lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status);
+ if (!ctx_obj_ptr || status.Fail())
+ return;
+
+ AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()),
+ current_id);
+
+ m_struct_vars->m_object_pointer_type =
+ TypeFromUser(ctx_obj_ptr->GetCompilerType());
+
+ return;
+ }
+
// Clang is looking for the type of "this"
- if (frame == NULL)
+ if (frame == nullptr)
return;
// Find the block that defines the function represented by "sym_ctx"
@@ -1020,6 +1041,21 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
static ConstString g_lldb_objc_class_name("$__lldb_objc_class");
if (name == g_lldb_objc_class_name) {
+ if (m_ctx_obj) {
+ Status status;
+ lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status);
+ if (!ctx_obj_ptr || status.Fail())
+ return;
+
+ AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()),
+ current_id);
+
+ m_struct_vars->m_object_pointer_type =
+ TypeFromUser(ctx_obj_ptr->GetCompilerType());
+
+ return;
+ }
+
// Clang is looking for the type of "*self"
if (!frame)
@@ -1241,7 +1277,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
}
}
if (target) {
- var = FindGlobalVariable(*target, module_sp, name, &namespace_decl, NULL);
+ var = FindGlobalVariable(*target, module_sp, name, &namespace_decl,
+ nullptr);
if (var) {
valobj = ValueObjectVariable::Create(target, var);
@@ -1398,8 +1435,8 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
}
if (sc_list.GetSize()) {
- Symbol *extern_symbol = NULL;
- Symbol *non_extern_symbol = NULL;
+ Symbol *extern_symbol = nullptr;
+ Symbol *non_extern_symbol = nullptr;
for (uint32_t index = 0, num_indices = sc_list.GetSize();
index < num_indices; ++index) {
@@ -1416,13 +1453,13 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr))
continue;
- AddOneFunction(context, sym_ctx.function, NULL, current_id);
+ AddOneFunction(context, sym_ctx.function, nullptr, current_id);
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);
- if (sym_ctx.symbol == NULL)
+ if (sym_ctx.symbol == nullptr)
continue;
}
@@ -1448,10 +1485,10 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
if (!context.m_found.function_with_type_info) {
if (extern_symbol) {
- AddOneFunction(context, NULL, extern_symbol, current_id);
+ AddOneFunction(context, nullptr, extern_symbol, current_id);
context.m_found.function = true;
} else if (non_extern_symbol) {
- AddOneFunction(context, NULL, non_extern_symbol, current_id);
+ AddOneFunction(context, nullptr, non_extern_symbol, current_id);
context.m_found.function = true;
}
}
@@ -1525,7 +1562,7 @@ void ClangExpressionDeclMap::FindExternalVisibleDecls(
context.m_found.variable = true;
}
}
- } while (0);
+ } while (false);
}
if (target && !context.m_found.variable && !namespace_decl) {
@@ -1687,7 +1724,7 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
bool is_reference = pt.IsReferenceType();
- NamedDecl *var_decl = NULL;
+ NamedDecl *var_decl = nullptr;
if (is_reference)
var_decl = context.AddVarDecl(pt);
else
@@ -1704,7 +1741,7 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
entity->GetParserVars(GetParserID());
parser_vars->m_parser_type = pt;
parser_vars->m_named_decl = var_decl;
- parser_vars->m_llvm_value = NULL;
+ parser_vars->m_llvm_value = nullptr;
parser_vars->m_lldb_value = var_location;
parser_vars->m_lldb_var = var;
@@ -1747,7 +1784,7 @@ void ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
->GetParserVars(GetParserID());
parser_vars->m_parser_type = parser_type;
parser_vars->m_named_decl = var_decl;
- parser_vars->m_llvm_value = NULL;
+ parser_vars->m_llvm_value = nullptr;
parser_vars->m_lldb_value.Clear();
if (log) {
@@ -1766,7 +1803,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
- if (target == NULL)
+ if (target == nullptr)
return;
ASTContext *scratch_ast_context =
@@ -1805,7 +1842,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
parser_vars->m_parser_type = parser_type;
parser_vars->m_named_decl = var_decl;
- parser_vars->m_llvm_value = NULL;
+ parser_vars->m_llvm_value = nullptr;
parser_vars->m_lldb_sym = &symbol;
if (log) {
@@ -1853,7 +1890,7 @@ bool ClangExpressionDeclMap::ResolveUnknownTypes() {
var_type.getAsOpaquePtr(),
ClangASTContext::GetASTContext(&var_decl->getASTContext()));
- lldb::opaque_compiler_type_t copied_type = 0;
+ lldb::opaque_compiler_type_t copied_type = nullptr;
if (m_ast_importer_sp) {
copied_type = m_ast_importer_sp->CopyType(
scratch_ast_context->getASTContext(), &var_decl->getASTContext(),
@@ -1926,7 +1963,7 @@ void ClangExpressionDeclMap::AddOneRegister(NameSearchContext &context,
entity->GetParserVars(GetParserID());
parser_vars->m_parser_type = parser_clang_type;
parser_vars->m_named_decl = var_decl;
- parser_vars->m_llvm_value = NULL;
+ parser_vars->m_llvm_value = nullptr;
parser_vars->m_lldb_value.Clear();
entity->m_flags |= ClangExpressionVariable::EVBareRegister;
@@ -1945,7 +1982,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- NamedDecl *function_decl = NULL;
+ NamedDecl *function_decl = nullptr;
Address fun_address;
CompilerType function_clang_type;
@@ -2105,7 +2142,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
}
parser_vars->m_named_decl = function_decl;
- parser_vars->m_llvm_value = NULL;
+ parser_vars->m_llvm_value = nullptr;
if (log) {
std::string function_str =
@@ -2125,7 +2162,7 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
}
void ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
- TypeFromUser &ut,
+ const TypeFromUser &ut,
unsigned int current_id) {
CompilerType copied_clang_type = GuardedCopyType(ut);
@@ -2158,7 +2195,7 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
CXXMethodDecl *method_decl =
ClangASTContext::GetASTContext(m_ast_context)
->AddMethodToCXXRecordType(
- copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", NULL,
+ copied_clang_type.GetOpaqueQualType(), "$__lldb_expr", nullptr,
method_type, lldb::eAccessPublic, is_virtual, is_static,
is_inline, is_explicit, is_attr_used, is_artificial);
@@ -2199,7 +2236,7 @@ void ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
}
void ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
- TypeFromUser &ut,
+ const TypeFromUser &ut,
unsigned int current_id) {
CompilerType copied_clang_type = GuardedCopyType(ut);
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
index 93fa57876bce..03b73e6be391 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -1,9 +1,8 @@
//===-- ClangExpressionDeclMap.h --------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -30,8 +29,7 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ClangExpressionDeclMap ClangExpressionDeclMap.h
+/// \class ClangExpressionDeclMap ClangExpressionDeclMap.h
/// "lldb/Expression/ClangExpressionDeclMap.h" Manages named entities that are
/// defined in LLDB's debug information.
///
@@ -54,236 +52,213 @@ namespace lldb_private {
///
/// Fourth and finally, it "dematerializes" the struct after the JITted code
/// has has executed, placing the new values back where it found the old ones.
-//----------------------------------------------------------------------
class ClangExpressionDeclMap : public ClangASTSource {
public:
- //------------------------------------------------------------------
/// Constructor
///
/// Initializes class variables.
///
- /// @param[in] keep_result_in_memory
+ /// \param[in] keep_result_in_memory
/// If true, inhibits the normal deallocation of the memory for
/// the result persistent variable, and instead marks the variable
/// as persisting.
///
- /// @param[in] delegate
+ /// \param[in] delegate
/// If non-NULL, use this delegate to report result values. This
/// allows the client ClangUserExpression to report a result.
///
- /// @param[in] exe_ctx
+ /// \param[in] exe_ctx
/// The execution context to use when parsing.
- //------------------------------------------------------------------
+ ///
+ /// \param[in] ctx_obj
+ /// If not empty, then expression is evaluated in context of this object.
+ /// See the comment to `UserExpression::Evaluate` for details.
ClangExpressionDeclMap(
bool keep_result_in_memory,
Materializer::PersistentVariableDelegate *result_delegate,
- ExecutionContext &exe_ctx);
+ ExecutionContext &exe_ctx,
+ ValueObject *ctx_obj);
- //------------------------------------------------------------------
/// Destructor
- //------------------------------------------------------------------
~ClangExpressionDeclMap() override;
- //------------------------------------------------------------------
/// Enable the state needed for parsing and IR transformation.
///
- /// @param[in] exe_ctx
+ /// \param[in] exe_ctx
/// The execution context to use when finding types for variables.
/// Also used to find a "scratch" AST context to store result types.
///
- /// @param[in] materializer
+ /// \param[in] materializer
/// If non-NULL, the materializer to populate with information about
/// the variables to use
///
- /// @return
+ /// \return
/// True if parsing is possible; false if it is unsafe to continue.
- //------------------------------------------------------------------
bool WillParse(ExecutionContext &exe_ctx, Materializer *materializer);
void InstallCodeGenerator(clang::ASTConsumer *code_gen);
- //------------------------------------------------------------------
/// [Used by ClangExpressionParser] For each variable that had an unknown
/// type at the beginning of parsing, determine its final type now.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
bool ResolveUnknownTypes();
- //------------------------------------------------------------------
/// Disable the state needed for parsing and IR transformation.
- //------------------------------------------------------------------
void DidParse();
- //------------------------------------------------------------------
/// [Used by IRForTarget] Add a variable to the list of persistent
/// variables for the process.
///
- /// @param[in] decl
+ /// \param[in] decl
/// The Clang declaration for the persistent variable, used for
/// lookup during parsing.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the persistent variable, usually $something.
///
- /// @param[in] type
+ /// \param[in] type
/// The type of the variable, in the Clang parser's context.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
bool AddPersistentVariable(const clang::NamedDecl *decl,
- const ConstString &name, TypeFromParser type,
+ ConstString name, TypeFromParser type,
bool is_result, bool is_lvalue);
- //------------------------------------------------------------------
/// [Used by IRForTarget] Add a variable to the struct that needs to
/// be materialized each time the expression runs.
///
- /// @param[in] decl
+ /// \param[in] decl
/// The Clang declaration for the variable.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the variable.
///
- /// @param[in] value
+ /// \param[in] value
/// The LLVM IR value for this variable.
///
- /// @param[in] size
+ /// \param[in] size
/// The size of the variable in bytes.
///
- /// @param[in] alignment
+ /// \param[in] alignment
/// The required alignment of the variable in bytes.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
- bool AddValueToStruct(const clang::NamedDecl *decl, const ConstString &name,
+ bool AddValueToStruct(const clang::NamedDecl *decl, ConstString name,
llvm::Value *value, size_t size,
lldb::offset_t alignment);
- //------------------------------------------------------------------
/// [Used by IRForTarget] Finalize the struct, laying out the position of
/// each object in it.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
bool DoStructLayout();
- //------------------------------------------------------------------
/// [Used by IRForTarget] Get general information about the laid-out struct
/// after DoStructLayout() has been called.
///
- /// @param[out] num_elements
+ /// \param[out] num_elements
/// The number of elements in the struct.
///
- /// @param[out] size
+ /// \param[out] size
/// The size of the struct, in bytes.
///
- /// @param[out] alignment
+ /// \param[out] alignment
/// The alignment of the struct, in bytes.
///
- /// @return
+ /// \return
/// True if the information could be retrieved; false otherwise.
- //------------------------------------------------------------------
bool GetStructInfo(uint32_t &num_elements, size_t &size,
lldb::offset_t &alignment);
- //------------------------------------------------------------------
/// [Used by IRForTarget] Get specific information about one field of the
/// laid-out struct after DoStructLayout() has been called.
///
- /// @param[out] decl
+ /// \param[out] decl
/// The parsed Decl for the field, as generated by ClangASTSource
/// on ClangExpressionDeclMap's behalf. In the case of the result
/// value, this will have the name $__lldb_result even if the
/// result value ends up having the name $1. This is an
/// implementation detail of IRForTarget.
///
- /// @param[out] value
+ /// \param[out] value
/// The IR value for the field (usually a GlobalVariable). In
/// the case of the result value, this will have the correct
/// name ($1, for instance). This is an implementation detail
/// of IRForTarget.
///
- /// @param[out] offset
+ /// \param[out] offset
/// The offset of the field from the beginning of the struct.
/// As long as the struct is aligned according to its required
/// alignment, this offset will align the field correctly.
///
- /// @param[out] name
+ /// \param[out] name
/// The name of the field as used in materialization.
///
- /// @param[in] index
+ /// \param[in] index
/// The index of the field about which information is requested.
///
- /// @return
+ /// \return
/// True if the information could be retrieved; false otherwise.
- //------------------------------------------------------------------
bool GetStructElement(const clang::NamedDecl *&decl, llvm::Value *&value,
lldb::offset_t &offset, ConstString &name,
uint32_t index);
- //------------------------------------------------------------------
/// [Used by IRForTarget] Get information about a function given its Decl.
///
- /// @param[in] decl
+ /// \param[in] decl
/// The parsed Decl for the Function, as generated by ClangASTSource
/// on ClangExpressionDeclMap's behalf.
///
- /// @param[out] ptr
+ /// \param[out] ptr
/// The absolute address of the function in the target.
///
- /// @return
+ /// \return
/// True if the information could be retrieved; false otherwise.
- //------------------------------------------------------------------
bool GetFunctionInfo(const clang::NamedDecl *decl, uint64_t &ptr);
- //------------------------------------------------------------------
/// [Used by IRForTarget] Get the address of a symbol given nothing but its
/// name.
///
- /// @param[in] target
+ /// \param[in] target
/// The target to find the symbol in. If not provided,
/// then the current parsing context's Target.
///
- /// @param[in] process
+ /// \param[in] process
/// The process to use. For Objective-C symbols, the process's
/// Objective-C language runtime may be queried if the process
/// is non-NULL.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the symbol.
///
- /// @param[in] module
+ /// \param[in] module
/// The module to limit the search to. This can be NULL
///
- /// @return
+ /// \return
/// Valid load address for the symbol
- //------------------------------------------------------------------
lldb::addr_t GetSymbolAddress(Target &target, Process *process,
- const ConstString &name,
- lldb::SymbolType symbol_type,
- Module *module = NULL);
+ ConstString name, lldb::SymbolType symbol_type,
+ Module *module = nullptr);
- lldb::addr_t GetSymbolAddress(const ConstString &name,
+ lldb::addr_t GetSymbolAddress(ConstString name,
lldb::SymbolType symbol_type);
- //------------------------------------------------------------------
/// [Used by IRInterpreter] Get basic target information.
///
- /// @param[out] byte_order
+ /// \param[out] byte_order
/// The byte order of the target.
///
- /// @param[out] address_byte_size
+ /// \param[out] address_byte_size
/// The size of a pointer in bytes.
///
- /// @return
+ /// \return
/// True if the information could be determined; false
/// otherwise.
- //------------------------------------------------------------------
struct TargetInfo {
lldb::ByteOrder byte_order;
size_t address_byte_size;
@@ -296,38 +271,34 @@ public:
};
TargetInfo GetTargetInfo();
- //------------------------------------------------------------------
/// [Used by ClangASTSource] Find all entities matching a given name, using
/// a NameSearchContext to make Decls for them.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext that can construct Decls for this name.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
void FindExternalVisibleDecls(NameSearchContext &context) override;
- //------------------------------------------------------------------
/// Find all entities matching a given name in a given module/namespace,
/// using a NameSearchContext to make Decls for them.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext that can construct Decls for this name.
///
- /// @param[in] module
+ /// \param[in] module
/// If non-NULL, the module to query.
///
- /// @param[in] namespace_decl
+ /// \param[in] namespace_decl
/// If valid and module is non-NULL, the parent namespace.
///
- /// @param[in] current_id
+ /// \param[in] current_id
/// The ID for the current FindExternalVisibleDecls invocation,
/// for logging purposes.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
void FindExternalVisibleDecls(NameSearchContext &context,
lldb::ModuleSP module,
CompilerDeclContext &namespace_decl,
@@ -344,10 +315,12 @@ private:
Materializer::PersistentVariableDelegate
*m_result_delegate; ///< If non-NULL, used to report expression results to
///ClangUserExpression.
+ ValueObject *m_ctx_obj; ///< If not empty, then expression is
+ ///evaluated in context of this object.
+ ///For details see the comment to
+ ///`UserExpression::Evaluate`.
- //----------------------------------------------------------------------
/// The following values should not live beyond parsing
- //----------------------------------------------------------------------
class ParserVars {
public:
ParserVars() {}
@@ -357,7 +330,7 @@ private:
return m_exe_ctx.GetTargetPtr();
else if (m_sym_ctx.target_sp)
m_sym_ctx.target_sp.get();
- return NULL;
+ return nullptr;
}
ExecutionContext m_exe_ctx; ///< The execution context to use when parsing.
@@ -380,27 +353,21 @@ private:
std::unique_ptr<ParserVars> m_parser_vars;
- //----------------------------------------------------------------------
/// Activate parser-specific variables
- //----------------------------------------------------------------------
void EnableParserVars() {
if (!m_parser_vars.get())
m_parser_vars = llvm::make_unique<ParserVars>();
}
- //----------------------------------------------------------------------
/// Deallocate parser-specific variables
- //----------------------------------------------------------------------
void DisableParserVars() { m_parser_vars.reset(); }
- //----------------------------------------------------------------------
/// The following values contain layout information for the materialized
/// struct, but are not specific to a single materialization
- //----------------------------------------------------------------------
struct StructVars {
StructVars()
: m_struct_alignment(0), m_struct_size(0), m_struct_laid_out(false),
- m_result_name(), m_object_pointer_type(NULL, NULL) {}
+ m_result_name(), m_object_pointer_type(nullptr, nullptr) {}
lldb::offset_t
m_struct_alignment; ///< The alignment of the struct in bytes.
@@ -416,202 +383,176 @@ private:
std::unique_ptr<StructVars> m_struct_vars;
- //----------------------------------------------------------------------
/// Activate struct variables
- //----------------------------------------------------------------------
void EnableStructVars() {
if (!m_struct_vars.get())
m_struct_vars.reset(new struct StructVars);
}
- //----------------------------------------------------------------------
/// Deallocate struct variables
- //----------------------------------------------------------------------
void DisableStructVars() { m_struct_vars.reset(); }
- //----------------------------------------------------------------------
/// Get this parser's ID for use in extracting parser- and JIT-specific data
/// from persistent variables.
- //----------------------------------------------------------------------
uint64_t GetParserID() { return (uint64_t) this; }
- //------------------------------------------------------------------
/// Given a target, find a variable that matches the given name and type.
///
- /// @param[in] target
+ /// \param[in] target
/// The target to use as a basis for finding the variable.
///
- /// @param[in] module
+ /// \param[in] module
/// If non-NULL, the module to search.
///
- /// @param[in] name
+ /// \param[in] name
/// The name as a plain C string.
///
- /// @param[in] namespace_decl
+ /// \param[in] namespace_decl
/// If non-NULL and module is non-NULL, the parent namespace.
///
- /// @param[in] type
+ /// \param[in] type
/// The required type for the variable. This function may be called
/// during parsing, in which case we don't know its type; hence the
/// default.
///
- /// @return
+ /// \return
/// The LLDB Variable found, or NULL if none was found.
- //------------------------------------------------------------------
lldb::VariableSP FindGlobalVariable(Target &target, lldb::ModuleSP &module,
- const ConstString &name,
+ ConstString name,
CompilerDeclContext *namespace_decl,
- TypeFromUser *type = NULL);
+ TypeFromUser *type = nullptr);
- //------------------------------------------------------------------
/// Get the value of a variable in a given execution context and return the
/// associated Types if needed.
///
- /// @param[in] var
+ /// \param[in] var
/// The variable to evaluate.
///
- /// @param[out] var_location
+ /// \param[out] var_location
/// The variable location value to fill in
///
- /// @param[out] found_type
+ /// \param[out] found_type
/// The type of the found value, as it was found in the user process.
/// This is only useful when the variable is being inspected on behalf
/// of the parser, hence the default.
///
- /// @param[out] parser_type
+ /// \param[out] parser_type
/// The type of the found value, as it was copied into the parser's
/// AST context. This is only useful when the variable is being
/// inspected on behalf of the parser, hence the default.
///
- /// @param[in] decl
+ /// \param[in] decl
/// The Decl to be looked up.
///
- /// @return
+ /// \return
/// Return true if the value was successfully filled in.
- //------------------------------------------------------------------
bool GetVariableValue(lldb::VariableSP &var,
lldb_private::Value &var_location,
- TypeFromUser *found_type = NULL,
- TypeFromParser *parser_type = NULL);
+ TypeFromUser *found_type = nullptr,
+ TypeFromParser *parser_type = nullptr);
- //------------------------------------------------------------------
/// Use the NameSearchContext to generate a Decl for the given LLDB
/// Variable, and put it in the Tuple list.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] var
+ /// \param[in] var
/// The LLDB Variable that needs a Decl.
///
- /// @param[in] valobj
+ /// \param[in] valobj
/// The LLDB ValueObject for that variable.
- //------------------------------------------------------------------
void AddOneVariable(NameSearchContext &context, lldb::VariableSP var,
lldb::ValueObjectSP valobj, unsigned int current_id);
- //------------------------------------------------------------------
/// Use the NameSearchContext to generate a Decl for the given persistent
/// variable, and put it in the list of found entities.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] pvar
+ /// \param[in] pvar
/// The persistent variable that needs a Decl.
///
- /// @param[in] current_id
+ /// \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);
- //------------------------------------------------------------------
/// 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.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] var
+ /// \param[in] var
/// The LLDB Variable that needs a Decl.
- //------------------------------------------------------------------
void AddOneGenericVariable(NameSearchContext &context, const Symbol &symbol,
unsigned int current_id);
- //------------------------------------------------------------------
/// Use the NameSearchContext to generate a Decl for the given function.
/// (Functions are not placed in the Tuple list.) Can handle both fully
/// typed functions and generic functions.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] fun
+ /// \param[in] fun
/// The Function that needs to be created. If non-NULL, this is
/// a fully-typed function.
///
- /// @param[in] sym
+ /// \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);
- //------------------------------------------------------------------
/// Use the NameSearchContext to generate a Decl for the given register.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] reg_info
+ /// \param[in] reg_info
/// The information corresponding to that register.
- //------------------------------------------------------------------
void AddOneRegister(NameSearchContext &context, const RegisterInfo *reg_info,
unsigned int current_id);
- //------------------------------------------------------------------
/// Use the NameSearchContext to generate a Decl for the given type. (Types
/// are not placed in the Tuple list.)
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] type
+ /// \param[in] type
/// The type that needs to be created.
- //------------------------------------------------------------------
- void AddOneType(NameSearchContext &context, TypeFromUser &type,
+ void AddOneType(NameSearchContext &context, const TypeFromUser &type,
unsigned int current_id);
- //------------------------------------------------------------------
/// Generate a Decl for "*this" and add a member function declaration to it
/// for the expression, then report it.
///
- /// @param[in] context
+ /// \param[in] context
/// The NameSearchContext to use when constructing the Decl.
///
- /// @param[in] type
+ /// \param[in] type
/// The type for *this.
- //------------------------------------------------------------------
- void AddThisType(NameSearchContext &context, TypeFromUser &type,
+ void AddThisType(NameSearchContext &context, const TypeFromUser &type,
unsigned int current_id);
- //------------------------------------------------------------------
/// Move a type out of the current ASTContext into another, but make sure to
/// export all components of the type also.
///
- /// @param[in] target
+ /// \param[in] target
/// The ClangASTContext to move to.
- /// @param[in] source
+ /// \param[in] source
/// The ClangASTContext to move from. This is assumed to be going away.
- /// @param[in] parser_type
+ /// \param[in] parser_type
/// The type as it appears in the source context.
///
- /// @return
+ /// \return
/// Returns the moved type, or an empty type if there was a problem.
- //------------------------------------------------------------------
TypeFromUser DeportType(ClangASTContext &target, ClangASTContext &source,
TypeFromParser parser_type);
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
index b5b640c9185f..48da5abb9126 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h
@@ -1,9 +1,8 @@
//===-- ClangExpressionHelper.h ---------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -24,9 +23,7 @@ namespace lldb_private {
class RecordingMemoryManager;
-//----------------------------------------------------------------------
// ClangExpressionHelper
-//----------------------------------------------------------------------
class ClangExpressionHelper : public ExpressionTypeSystemHelper {
public:
static bool classof(const ExpressionTypeSystemHelper *ts) {
@@ -37,25 +34,19 @@ public:
: ExpressionTypeSystemHelper(
ExpressionTypeSystemHelper::LLVMCastKind::eKindClangHelper) {}
- //------------------------------------------------------------------
/// Destructor
- //------------------------------------------------------------------
virtual ~ClangExpressionHelper() {}
- //------------------------------------------------------------------
/// Return the object that the parser should use when resolving external
/// values. May be NULL if everything should be self-contained.
- //------------------------------------------------------------------
virtual ClangExpressionDeclMap *DeclMap() = 0;
- //------------------------------------------------------------------
/// Return the object that the parser should allow to access ASTs.
/// May be NULL if the ASTs do not need to be transformed.
///
- /// @param[in] passthrough
+ /// \param[in] passthrough
/// The ASTConsumer that the returned transformer should send
/// the ASTs to after transformation.
- //------------------------------------------------------------------
virtual clang::ASTConsumer *
ASTTransformer(clang::ASTConsumer *passthrough) = 0;
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 6650c0db967f..7d13891ded8d 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -1,19 +1,16 @@
//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 <cctype>
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/DiagnosticIDs.h"
-#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
@@ -39,15 +36,11 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TargetSelect.h"
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wglobal-constructors"
-#include "llvm/ExecutionEngine/MCJIT.h"
-#pragma clang diagnostic pop
-
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/DynamicLibrary.h"
@@ -58,19 +51,25 @@
#include "ClangDiagnostic.h"
#include "ClangExpressionParser.h"
+#include "ClangUserExpression.h"
+#include "ASTUtils.h"
#include "ClangASTSource.h"
+#include "ClangDiagnostic.h"
#include "ClangExpressionDeclMap.h"
#include "ClangExpressionHelper.h"
+#include "ClangExpressionParser.h"
+#include "ClangHost.h"
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
+#include "IRDynamicChecks.h"
#include "IRForTarget.h"
+#include "ModuleDependencyCollector.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Expression/IRInterpreter.h"
#include "lldb/Host/File.h"
@@ -79,17 +78,22 @@
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Language.h"
-#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringList.h"
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+#include <cctype>
+#include <memory>
+
using namespace clang;
using namespace llvm;
using namespace lldb_private;
@@ -111,24 +115,19 @@ public:
void moduleImport(SourceLocation import_location, clang::ModuleIdPath path,
const clang::Module * /*null*/) override {
- std::vector<ConstString> string_path;
+ SourceModule module;
- for (const std::pair<IdentifierInfo *, SourceLocation> &component : path) {
- string_path.push_back(ConstString(component.first->getName()));
- }
+ for (const std::pair<IdentifierInfo *, SourceLocation> &component : path)
+ module.path.push_back(ConstString(component.first->getName()));
StreamString error_stream;
ClangModulesDeclVendor::ModuleVector exported_modules;
-
- if (!m_decl_vendor.AddModule(string_path, &exported_modules,
- m_error_stream)) {
+ if (!m_decl_vendor.AddModule(module, &exported_modules, m_error_stream))
m_has_errors = true;
- }
- for (ClangModulesDeclVendor::ModuleID module : exported_modules) {
+ for (ClangModulesDeclVendor::ModuleID module : exported_modules)
m_persistent_vars.AddHandLoadedClangModule(module);
- }
}
bool hasErrors() { return m_has_errors; }
@@ -150,7 +149,7 @@ public:
}
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const clang::Diagnostic &Info) {
+ const clang::Diagnostic &Info) override {
if (m_manager) {
llvm::SmallVector<char, 32> diag_str;
Info.FormatDiagnostic(diag_str);
@@ -214,15 +213,58 @@ private:
std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough;
};
+static void
+SetupModuleHeaderPaths(CompilerInstance *compiler,
+ std::vector<ConstString> include_directories,
+ lldb::TargetSP target_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts();
+
+ for (ConstString dir : include_directories) {
+ search_opts.AddPath(dir.AsCString(), frontend::System, false, true);
+ LLDB_LOG(log, "Added user include dir: {0}", dir);
+ }
+
+ llvm::SmallString<128> module_cache;
+ auto props = ModuleList::GetGlobalModuleListProperties();
+ props.GetClangModulesCachePath().GetPath(module_cache);
+ search_opts.ModuleCachePath = module_cache.str();
+ LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str());
+
+ FileSpec clang_resource_dir = GetClangResourceDir();
+ std::string resource_dir = clang_resource_dir.GetPath();
+ if (FileSystem::Instance().IsDirectory(resource_dir)) {
+ search_opts.ResourceDir = resource_dir;
+ std::string resource_include = resource_dir + "/include";
+ search_opts.AddPath(resource_include, frontend::System, false, true);
+
+ LLDB_LOG(log, "Added resource include dir: {0}", resource_include);
+ }
+
+ search_opts.ImplicitModuleMaps = true;
+
+ std::vector<std::string> system_include_directories =
+ target_sp->GetPlatform()->GetSystemIncludeDirectories(
+ lldb::eLanguageTypeC_plus_plus);
+
+ for (const std::string &include_dir : system_include_directories) {
+ search_opts.AddPath(include_dir, frontend::System, false, true);
+
+ LLDB_LOG(log, "Added system include dir: {0}", include_dir);
+ }
+}
+
//===----------------------------------------------------------------------===//
// Implementation of ClangExpressionParser
//===----------------------------------------------------------------------===//
-ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
- Expression &expr,
- bool generate_debug_info)
+ClangExpressionParser::ClangExpressionParser(
+ ExecutionContextScope *exe_scope, Expression &expr,
+ bool generate_debug_info, std::vector<ConstString> include_directories)
: ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
- m_pp_callbacks(nullptr) {
+ m_pp_callbacks(nullptr),
+ m_include_directories(std::move(include_directories)) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
// We can't compile expressions without a target. So if the exe_scope is
@@ -249,6 +291,22 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
// 1. Create a new compiler instance.
m_compiler.reset(new CompilerInstance());
+
+ // When capturing a reproducer, hook up the file collector with clang to
+ // collector modules and headers.
+ if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
+ repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
+ m_compiler->setModuleDepCollector(
+ std::make_shared<ModuleDependencyCollectorAdaptor>(
+ fp.GetFileCollector()));
+ DependencyOutputOptions &opts = m_compiler->getDependencyOutputOpts();
+ opts.IncludeSystemHeaders = true;
+ opts.IncludeModuleFiles = true;
+ }
+
+ // Make sure clang uses the same VFS as LLDB.
+ m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
+
lldb::LanguageType frame_lang =
expr.Language(); // defaults to lldb::eLanguageTypeUnknown
bool overridden_target_opts = false;
@@ -363,6 +421,7 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
// 5. Set language options.
lldb::LanguageType language = expr.Language();
+ LangOptions &lang_opts = m_compiler->getLangOpts();
switch (language) {
case lldb::eLanguageTypeC:
@@ -374,13 +433,13 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
// For now, the expression parser must use C++ anytime the language is a C
// family language, because the expression parser uses features of C++ to
// capture values.
- m_compiler->getLangOpts().CPlusPlus = true;
+ lang_opts.CPlusPlus = true;
break;
case lldb::eLanguageTypeObjC:
- m_compiler->getLangOpts().ObjC = true;
+ lang_opts.ObjC = true;
// FIXME: the following language option is a temporary workaround,
// to "ask for ObjC, get ObjC++" (see comment above).
- m_compiler->getLangOpts().CPlusPlus = true;
+ lang_opts.CPlusPlus = true;
// Clang now sets as default C++14 as the default standard (with
// GNU extensions), so we do the same here to avoid mismatches that
@@ -388,71 +447,92 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
// as it's a C++11 feature). Currently lldb evaluates C++14 as C++11 (see
// two lines below) so we decide to be consistent with that, but this could
// be re-evaluated in the future.
- m_compiler->getLangOpts().CPlusPlus11 = true;
+ lang_opts.CPlusPlus11 = true;
break;
case lldb::eLanguageTypeC_plus_plus:
case lldb::eLanguageTypeC_plus_plus_11:
case lldb::eLanguageTypeC_plus_plus_14:
- m_compiler->getLangOpts().CPlusPlus11 = true;
+ lang_opts.CPlusPlus11 = true;
m_compiler->getHeaderSearchOpts().UseLibcxx = true;
LLVM_FALLTHROUGH;
case lldb::eLanguageTypeC_plus_plus_03:
- m_compiler->getLangOpts().CPlusPlus = true;
+ lang_opts.CPlusPlus = true;
if (process_sp)
- m_compiler->getLangOpts().ObjC =
+ lang_opts.ObjC =
process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr;
break;
case lldb::eLanguageTypeObjC_plus_plus:
case lldb::eLanguageTypeUnknown:
default:
- m_compiler->getLangOpts().ObjC = true;
- m_compiler->getLangOpts().CPlusPlus = true;
- m_compiler->getLangOpts().CPlusPlus11 = true;
+ lang_opts.ObjC = true;
+ lang_opts.CPlusPlus = true;
+ lang_opts.CPlusPlus11 = true;
m_compiler->getHeaderSearchOpts().UseLibcxx = true;
break;
}
- m_compiler->getLangOpts().Bool = true;
- m_compiler->getLangOpts().WChar = true;
- m_compiler->getLangOpts().Blocks = true;
- m_compiler->getLangOpts().DebuggerSupport =
+ lang_opts.Bool = true;
+ lang_opts.WChar = true;
+ lang_opts.Blocks = true;
+ lang_opts.DebuggerSupport =
true; // Features specifically for debugger clients
if (expr.DesiredResultType() == Expression::eResultTypeId)
- m_compiler->getLangOpts().DebuggerCastResultToId = true;
+ lang_opts.DebuggerCastResultToId = true;
- m_compiler->getLangOpts().CharIsSigned =
- ArchSpec(m_compiler->getTargetOpts().Triple.c_str())
- .CharIsSignedByDefault();
+ lang_opts.CharIsSigned = ArchSpec(m_compiler->getTargetOpts().Triple.c_str())
+ .CharIsSignedByDefault();
// Spell checking is a nice feature, but it ends up completing a lot of types
// that we didn't strictly speaking need to complete. As a result, we spend a
// long time parsing and importing debug information.
- m_compiler->getLangOpts().SpellChecking = false;
+ lang_opts.SpellChecking = false;
+
+ auto *clang_expr = dyn_cast<ClangUserExpression>(&m_expr);
+ if (clang_expr && clang_expr->DidImportCxxModules()) {
+ LLDB_LOG(log, "Adding lang options for importing C++ modules");
+
+ lang_opts.Modules = true;
+ // We want to implicitly build modules.
+ lang_opts.ImplicitModules = true;
+ // To automatically import all submodules when we import 'std'.
+ lang_opts.ModulesLocalVisibility = false;
+
+ // We use the @import statements, so we need this:
+ // FIXME: We could use the modules-ts, but that currently doesn't work.
+ lang_opts.ObjC = true;
+
+ // Options we need to parse libc++ code successfully.
+ // FIXME: We should ask the driver for the appropriate default flags.
+ lang_opts.GNUMode = true;
+ lang_opts.GNUKeywords = true;
+ lang_opts.DoubleSquareBracketAttributes = true;
+ lang_opts.CPlusPlus11 = true;
+
+ SetupModuleHeaderPaths(m_compiler.get(), m_include_directories,
+ target_sp);
+ }
- if (process_sp && m_compiler->getLangOpts().ObjC) {
- if (process_sp->GetObjCLanguageRuntime()) {
- if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() ==
+ if (process_sp && lang_opts.ObjC) {
+ if (auto *runtime = ObjCLanguageRuntime::Get(*process_sp)) {
+ if (runtime->GetRuntimeVersion() ==
ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2)
- m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX,
- VersionTuple(10, 7));
+ lang_opts.ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
else
- m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX,
- VersionTuple(10, 7));
+ lang_opts.ObjCRuntime.set(ObjCRuntime::FragileMacOSX,
+ VersionTuple(10, 7));
- if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing())
- m_compiler->getLangOpts().DebuggerObjCLiteral = true;
+ if (runtime->HasNewLiteralsAndIndexing())
+ lang_opts.DebuggerObjCLiteral = true;
}
}
- m_compiler->getLangOpts().ThreadsafeStatics = false;
- m_compiler->getLangOpts().AccessControl =
- false; // Debuggers get universal access
- m_compiler->getLangOpts().DollarIdents =
- true; // $ indicates a persistent variable name
+ lang_opts.ThreadsafeStatics = false;
+ lang_opts.AccessControl = false; // Debuggers get universal access
+ lang_opts.DollarIdents = true; // $ indicates a persistent variable name
// We enable all builtin functions beside the builtins from libc/libm (e.g.
// 'fopen'). Those libc functions are already correctly handled by LLDB, and
// additionally enabling them as expandable builtins is breaking Clang.
- m_compiler->getLangOpts().NoBuiltin = true;
+ lang_opts.NoBuiltin = true;
// Set CodeGen options
m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
@@ -483,14 +563,9 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter);
// 7. Set up the source management objects inside the compiler
-
- clang::FileSystemOptions file_system_options;
- m_file_manager.reset(new clang::FileManager(file_system_options));
-
- if (!m_compiler->hasSourceManager())
- m_compiler->createSourceManager(*m_file_manager.get());
-
m_compiler->createFileManager();
+ if (!m_compiler->hasSourceManager())
+ m_compiler->createSourceManager(m_compiler->getFileManager());
m_compiler->createPreprocessor(TU_Complete);
if (ClangModulesDeclVendor *decl_vendor =
@@ -517,17 +592,6 @@ ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
m_compiler->createASTContext();
clang::ASTContext &ast_context = m_compiler->getASTContext();
- ClangExpressionHelper *type_system_helper =
- dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
- ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
-
- if (decl_map) {
- llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(
- decl_map->CreateProxy());
- decl_map->InstallASTContext(ast_context, m_compiler->getFileManager());
- ast_context.setExternalSource(ast_source);
- }
-
m_ast_context.reset(
new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str()));
m_ast_context->setASTContext(&ast_context);
@@ -545,13 +609,11 @@ ClangExpressionParser::~ClangExpressionParser() {}
namespace {
-//----------------------------------------------------------------------
-/// @class CodeComplete
+/// \class CodeComplete
///
/// A code completion consumer for the clang Sema that is responsible for
/// creating the completion suggestions when a user requests completion
/// of an incomplete `expr` invocation.
-//----------------------------------------------------------------------
class CodeComplete : public CodeCompleteConsumer {
CodeCompletionTUInfo m_info;
@@ -624,20 +686,20 @@ class CodeComplete : public CodeCompleteConsumer {
public:
/// Constructs a CodeComplete consumer that can be attached to a Sema.
- /// @param[out] matches
+ /// \param[out] matches
/// The list of matches that the lldb completion API expects as a result.
/// This may already contain matches, so it's only allowed to append
/// to this variable.
- /// @param[out] expr
+ /// \param[out] expr
/// The whole expression string that we are currently parsing. This
/// string needs to be equal to the input the user typed, and NOT the
/// final code that Clang is parsing.
- /// @param[out] position
+ /// \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)
- : CodeCompleteConsumer(CodeCompleteOptions(), false),
+ : CodeCompleteConsumer(CodeCompleteOptions()),
m_info(std::make_shared<GlobalCodeCompletionAllocator>()), m_expr(expr),
m_position(position), m_request(request), m_desc_policy(ops) {
@@ -653,7 +715,7 @@ public:
}
/// Deregisters and destroys this code-completion consumer.
- virtual ~CodeComplete() {}
+ ~CodeComplete() override {}
/// \name Code-completion filtering
/// Check if the result should be filtered out.
@@ -788,8 +850,8 @@ bool ClangExpressionParser::Complete(CompletionRequest &request, unsigned line,
// To actually get the raw user input here, we have to cast our expression to
// the LLVMUserExpression which exposes the right API. This should never fail
// as we always have a ClangUserExpression whenever we call this.
- LLVMUserExpression &llvm_expr = *static_cast<LLVMUserExpression *>(&m_expr);
- CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr.GetUserText(),
+ ClangUserExpression *llvm_expr = cast<ClangUserExpression>(&m_expr);
+ CodeComplete CC(request, m_compiler->getLangOpts(), llvm_expr->GetUserText(),
typed_pos);
// We don't need a code generator for parsing.
m_code_generator.reset();
@@ -848,9 +910,9 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
if (file.Write(expr_text, bytes_written).Success()) {
if (bytes_written == expr_text_len) {
file.Close();
- source_mgr.setMainFileID(
- source_mgr.createFileID(m_file_manager->getFile(result_path),
- SourceLocation(), SrcMgr::C_User));
+ source_mgr.setMainFileID(source_mgr.createFileID(
+ m_compiler->getFileManager().getFile(result_path),
+ SourceLocation(), SrcMgr::C_User));
created_main_file = true;
}
}
@@ -859,7 +921,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
if (!created_main_file) {
std::unique_ptr<MemoryBuffer> memory_buffer =
- MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__);
+ MemoryBuffer::getMemBufferCopy(expr_text, "<lldb-expr>");
source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer)));
}
@@ -869,12 +931,6 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
ClangExpressionHelper *type_system_helper =
dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
- ASTConsumer *ast_transformer =
- type_system_helper->ASTTransformer(m_code_generator.get());
-
- if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap())
- decl_map->InstallCodeGenerator(m_code_generator.get());
-
// If we want to parse for code completion, we need to attach our code
// completion consumer to the Sema and specify a completion position.
// While parsing the Sema will call this consumer with the provided
@@ -889,18 +945,72 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager,
PP.SetCodeCompletionPoint(main_file, completion_line, completion_column);
}
+ ASTConsumer *ast_transformer =
+ type_system_helper->ASTTransformer(m_code_generator.get());
+
+ std::unique_ptr<clang::ASTConsumer> Consumer;
if (ast_transformer) {
- ast_transformer->Initialize(m_compiler->getASTContext());
- ParseAST(m_compiler->getPreprocessor(), ast_transformer,
- m_compiler->getASTContext(), false, TU_Complete,
- completion_consumer);
+ Consumer.reset(new ASTConsumerForwarder(ast_transformer));
+ } else if (m_code_generator) {
+ Consumer.reset(new ASTConsumerForwarder(m_code_generator.get()));
} else {
- m_code_generator->Initialize(m_compiler->getASTContext());
- ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(),
- m_compiler->getASTContext(), false, TU_Complete,
- completion_consumer);
+ Consumer.reset(new ASTConsumer());
+ }
+
+ clang::ASTContext &ast_context = m_compiler->getASTContext();
+
+ m_compiler->setSema(new Sema(m_compiler->getPreprocessor(), ast_context,
+ *Consumer, TU_Complete, completion_consumer));
+ m_compiler->setASTConsumer(std::move(Consumer));
+
+ if (ast_context.getLangOpts().Modules) {
+ m_compiler->createModuleManager();
+ m_ast_context->setSema(&m_compiler->getSema());
}
+ ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
+ if (decl_map) {
+ decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer());
+
+ clang::ExternalASTSource *ast_source = decl_map->CreateProxy();
+
+ if (ast_context.getExternalSource()) {
+ auto module_wrapper =
+ new ExternalASTSourceWrapper(ast_context.getExternalSource());
+
+ auto ast_source_wrapper = new ExternalASTSourceWrapper(ast_source);
+
+ auto multiplexer =
+ new SemaSourceWithPriorities(*module_wrapper, *ast_source_wrapper);
+ IntrusiveRefCntPtr<ExternalASTSource> Source(multiplexer);
+ ast_context.setExternalSource(Source);
+ } else {
+ ast_context.setExternalSource(ast_source);
+ }
+ decl_map->InstallASTContext(ast_context, m_compiler->getFileManager());
+ }
+
+ // Check that the ASTReader is properly attached to ASTContext and Sema.
+ if (ast_context.getLangOpts().Modules) {
+ assert(m_compiler->getASTContext().getExternalSource() &&
+ "ASTContext doesn't know about the ASTReader?");
+ assert(m_compiler->getSema().getExternalSource() &&
+ "Sema doesn't know about the ASTReader?");
+ }
+
+ {
+ llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(
+ &m_compiler->getSema());
+ ParseAST(m_compiler->getSema(), false, false);
+ }
+
+ // Make sure we have no pointer to the Sema we are about to destroy.
+ if (ast_context.getLangOpts().Modules)
+ m_ast_context->setSema(nullptr);
+ // Destroy the Sema. This is necessary because we want to emulate the
+ // original behavior of ParseAST (which also destroys the Sema after parsing).
+ m_compiler->setSema(nullptr);
+
diag_buf->EndSourceFile();
unsigned num_errors = diag_buf->getNumErrors();
@@ -1050,10 +1160,10 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
lldb_private::Status err;
- std::unique_ptr<llvm::Module> llvm_module_ap(
+ std::unique_ptr<llvm::Module> llvm_module_up(
m_code_generator->ReleaseModule());
- if (!llvm_module_ap.get()) {
+ if (!llvm_module_up) {
err.SetErrorToGenericError();
err.SetErrorString("IR doesn't contain a module");
return err;
@@ -1064,7 +1174,7 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
if (execution_policy != eExecutionPolicyTopLevel) {
// Find the actual name of the function (it's often mangled somehow)
- if (!FindFunctionInModule(function_name, llvm_module_ap.get(),
+ if (!FindFunctionInModule(function_name, llvm_module_up.get(),
m_expr.FunctionName())) {
err.SetErrorToGenericError();
err.SetErrorStringWithFormat("Couldn't find %s() in the module",
@@ -1105,14 +1215,14 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
"expression module '%s'",
__FUNCTION__, m_expr.FunctionName());
- custom_passes.EarlyPasses->run(*llvm_module_ap);
+ custom_passes.EarlyPasses->run(*llvm_module_up);
}
- execution_unit_sp.reset(
- new IRExecutionUnit(m_llvm_context, // handed off here
- llvm_module_ap, // handed off here
- function_name, exe_ctx.GetTargetSP(), sc,
- m_compiler->getTargetOpts().Features));
+ execution_unit_sp = std::make_shared<IRExecutionUnit>(
+ m_llvm_context, // handed off here
+ llvm_module_up, // handed off here
+ function_name, exe_ctx.GetTargetSP(), sc,
+ m_compiler->getTargetOpts().Features);
ClangExpressionHelper *type_system_helper =
dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
@@ -1120,7 +1230,7 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
type_system_helper->DeclMap(); // result can be NULL
if (decl_map) {
- Stream *error_stream = NULL;
+ Stream *error_stream = nullptr;
Target *target = exe_ctx.GetTargetPtr();
error_stream = target->GetDebugger().GetErrorFile().get();
@@ -1172,8 +1282,8 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
(execution_policy != eExecutionPolicyTopLevel && !can_interpret)) {
if (m_expr.NeedsValidation() && process) {
if (!process->GetDynamicCheckers()) {
- DynamicCheckerFunctions *dynamic_checkers =
- new DynamicCheckerFunctions();
+ ClangDynamicCheckerFunctions *dynamic_checkers =
+ new ClangDynamicCheckerFunctions();
DiagnosticManager install_diagnostics;
@@ -1189,27 +1299,30 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution(
process->SetDynamicCheckers(dynamic_checkers);
if (log)
- log->Printf("== [ClangUserExpression::Evaluate] Finished "
- "installing dynamic checkers ==");
+ log->Printf("== [ClangExpressionParser::PrepareForExecution] "
+ "Finished installing dynamic checkers ==");
}
- IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(),
- function_name.AsCString());
+ if (auto *checker_funcs = llvm::dyn_cast<ClangDynamicCheckerFunctions>(
+ process->GetDynamicCheckers())) {
+ IRDynamicChecks ir_dynamic_checks(*checker_funcs,
+ function_name.AsCString());
- llvm::Module *module = execution_unit_sp->GetModule();
- if (!module || !ir_dynamic_checks.runOnModule(*module)) {
- err.SetErrorToGenericError();
- err.SetErrorString("Couldn't add dynamic checks to the expression");
- return err;
- }
+ llvm::Module *module = execution_unit_sp->GetModule();
+ if (!module || !ir_dynamic_checks.runOnModule(*module)) {
+ err.SetErrorToGenericError();
+ err.SetErrorString("Couldn't add dynamic checks to the expression");
+ return err;
+ }
- if (custom_passes.LatePasses) {
- if (log)
- log->Printf("%s - Running Late IR Passes from LanguageRuntime on "
- "expression module '%s'",
- __FUNCTION__, m_expr.FunctionName());
+ if (custom_passes.LatePasses) {
+ if (log)
+ log->Printf("%s - Running Late IR Passes from LanguageRuntime on "
+ "expression module '%s'",
+ __FUNCTION__, m_expr.FunctionName());
- custom_passes.LatePasses->run(*module);
+ custom_passes.LatePasses->run(*module);
+ }
}
}
}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
index 03ff55f614d5..a42c2190ffb8 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -1,9 +1,8 @@
//===-- ClangExpressionParser.h ---------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -28,8 +27,7 @@ namespace lldb_private {
class IRExecutionUnit;
-//----------------------------------------------------------------------
-/// @class ClangExpressionParser ClangExpressionParser.h
+/// \class ClangExpressionParser ClangExpressionParser.h
/// "lldb/Expression/ClangExpressionParser.h" Encapsulates an instance of
/// Clang that can parse expressions.
///
@@ -38,140 +36,130 @@ class IRExecutionUnit;
/// as a glorified parameter list, performing the required parsing and
/// conversion to formats (DWARF bytecode, or JIT compiled machine code) that
/// can be executed.
-//----------------------------------------------------------------------
class ClangExpressionParser : public ExpressionParser {
public:
- //------------------------------------------------------------------
/// Constructor
///
/// Initializes class variables.
///
- /// @param[in] exe_scope,
+ /// \param[in] exe_scope,
/// If non-NULL, an execution context scope that can help to
/// correctly create an expression with a valid process for
/// optional tuning Objective-C runtime support. Can be NULL.
///
- /// @param[in] expr
+ /// \param[in] expr
/// The expression to be parsed.
- //------------------------------------------------------------------
+ ///
+ /// @param[in] include_directories
+ /// List of include directories that should be used when parsing the
+ /// expression.
ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr,
- bool generate_debug_info);
+ bool generate_debug_info,
+ std::vector<ConstString> include_directories = {});
- //------------------------------------------------------------------
/// Destructor
- //------------------------------------------------------------------
~ClangExpressionParser() override;
bool Complete(CompletionRequest &request, unsigned line, unsigned pos,
unsigned typed_pos) override;
- //------------------------------------------------------------------
/// Parse a single expression and convert it to IR using Clang. Don't wrap
/// the expression in anything at all.
///
- /// @param[in] diagnostic_manager
+ /// \param[in] diagnostic_manager
/// The diagnostic manager to report errors to.
///
- /// @return
+ /// \return
/// The number of errors encountered during parsing. 0 means
/// success.
- //------------------------------------------------------------------
unsigned Parse(DiagnosticManager &diagnostic_manager) override;
bool RewriteExpression(DiagnosticManager &diagnostic_manager) override;
- //------------------------------------------------------------------
/// Ready an already-parsed expression for execution, possibly evaluating it
/// statically.
///
- /// @param[out] func_addr
+ /// \param[out] func_addr
/// The address to which the function has been written.
///
- /// @param[out] func_end
+ /// \param[out] func_end
/// The end of the function's allocated memory region. (func_addr
/// and func_end do not delimit an allocated region; the allocated
/// region may begin before func_addr.)
///
- /// @param[in] execution_unit_sp
+ /// \param[in] execution_unit_sp
/// After parsing, ownership of the execution unit for
/// for the expression is handed to this shared pointer.
///
- /// @param[in] exe_ctx
+ /// \param[in] exe_ctx
/// The execution context to write the function into.
///
- /// @param[out] evaluated_statically
+ /// \param[out] evaluated_statically
/// Set to true if the expression could be interpreted statically;
/// untouched otherwise.
///
- /// @param[out] const_result
+ /// \param[out] const_result
/// If the result of the expression is constant, and the
/// expression has no side effects, this is set to the result of the
/// expression.
///
- /// @param[in] execution_policy
+ /// \param[in] execution_policy
/// Determines whether the expression must be JIT-compiled, must be
/// evaluated statically, or whether this decision may be made
/// opportunistically.
///
- /// @return
+ /// \return
/// An error code indicating the success or failure of the operation.
/// Test with Success().
- //------------------------------------------------------------------
Status
PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end,
lldb::IRExecutionUnitSP &execution_unit_sp,
ExecutionContext &exe_ctx, bool &can_interpret,
lldb_private::ExecutionPolicy execution_policy) override;
- //------------------------------------------------------------------
/// Run all static initializers for an execution unit.
///
- /// @param[in] execution_unit_sp
+ /// \param[in] execution_unit_sp
/// The execution unit.
///
- /// @param[in] exe_ctx
+ /// \param[in] exe_ctx
/// The execution context to use when running them. Thread can't be null.
///
- /// @return
+ /// \return
/// The error code indicating the
- //------------------------------------------------------------------
Status RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp,
ExecutionContext &exe_ctx);
- //------------------------------------------------------------------
/// Returns a string representing current ABI.
///
- /// @param[in] target_arch
+ /// \param[in] target_arch
/// The target architecture.
///
- /// @return
+ /// \return
/// A string representing target ABI for the current architecture.
- //-------------------------------------------------------------------
std::string GetClangTargetABI(const ArchSpec &target_arch);
private:
- //------------------------------------------------------------------
/// Parses the expression.
///
- /// @param[in] diagnostic_manager
+ /// \param[in] diagnostic_manager
/// The diagnostic manager that should receive the diagnostics
/// from the parsing process.
///
- /// @param[in] completion
+ /// \param[in] completion
/// The completion consumer that should be used during parsing
/// (or a nullptr if no consumer should be attached).
///
- /// @param[in] completion_line
+ /// \param[in] completion_line
/// The line in which the completion marker should be placed.
/// The first line is represented by the value 0.
///
- /// @param[in] completion_column
+ /// \param[in] completion_column
/// The column in which the completion marker should be placed.
/// The first column is represented by the value 0.
///
- /// @return
+ /// \return
/// The number of parsing errors.
- //-------------------------------------------------------------------
unsigned ParseInternal(DiagnosticManager &diagnostic_manager,
clang::CodeCompleteConsumer *completion = nullptr,
unsigned completion_line = 0,
@@ -179,8 +167,6 @@ private:
std::unique_ptr<llvm::LLVMContext>
m_llvm_context; ///< The LLVM context to generate IR into
- std::unique_ptr<clang::FileManager>
- m_file_manager; ///< The Clang file manager object used by the compiler
std::unique_ptr<clang::CompilerInstance>
m_compiler; ///< The Clang compiler used to parse expressions into IR
std::unique_ptr<clang::CodeGenerator>
@@ -190,6 +176,8 @@ private:
LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor
///encounters module imports
std::unique_ptr<ClangASTContext> m_ast_context;
+
+ std::vector<ConstString> m_include_directories;
};
}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
new file mode 100644
index 000000000000..f513b1eea360
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -0,0 +1,497 @@
+//===-- ClangExpressionSourceCode.cpp ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangExpressionSourceCode.h"
+
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
+#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/DebugMacros.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb_private;
+
+const char *ClangExpressionSourceCode::g_expression_prefix = R"(
+#ifndef NULL
+#define NULL (__null)
+#endif
+#ifndef Nil
+#define Nil (__null)
+#endif
+#ifndef nil
+#define nil (__null)
+#endif
+#ifndef YES
+#define YES ((BOOL)1)
+#endif
+#ifndef NO
+#define NO ((BOOL)0)
+#endif
+typedef __INT8_TYPE__ int8_t;
+typedef __UINT8_TYPE__ uint8_t;
+typedef __INT16_TYPE__ int16_t;
+typedef __UINT16_TYPE__ uint16_t;
+typedef __INT32_TYPE__ int32_t;
+typedef __UINT32_TYPE__ uint32_t;
+typedef __INT64_TYPE__ int64_t;
+typedef __UINT64_TYPE__ uint64_t;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef unsigned short unichar;
+extern "C"
+{
+ int printf(const char * __restrict, ...);
+}
+)";
+
+static const char *c_start_marker = " /*LLDB_BODY_START*/\n ";
+static const char *c_end_marker = ";\n /*LLDB_BODY_END*/\n";
+
+namespace {
+
+class AddMacroState {
+ enum State {
+ CURRENT_FILE_NOT_YET_PUSHED,
+ CURRENT_FILE_PUSHED,
+ CURRENT_FILE_POPPED
+ };
+
+public:
+ AddMacroState(const FileSpec &current_file, const uint32_t current_file_line)
+ : m_state(CURRENT_FILE_NOT_YET_PUSHED), m_current_file(current_file),
+ m_current_file_line(current_file_line) {}
+
+ void StartFile(const FileSpec &file) {
+ m_file_stack.push_back(file);
+ if (file == m_current_file)
+ m_state = CURRENT_FILE_PUSHED;
+ }
+
+ void EndFile() {
+ if (m_file_stack.size() == 0)
+ return;
+
+ FileSpec old_top = m_file_stack.back();
+ m_file_stack.pop_back();
+ if (old_top == m_current_file)
+ m_state = CURRENT_FILE_POPPED;
+ }
+
+ // An entry is valid if it occurs before the current line in the current
+ // file.
+ bool IsValidEntry(uint32_t line) {
+ switch (m_state) {
+ case CURRENT_FILE_NOT_YET_PUSHED:
+ return true;
+ case CURRENT_FILE_PUSHED:
+ // If we are in file included in the current file, the entry should be
+ // added.
+ if (m_file_stack.back() != m_current_file)
+ return true;
+
+ return line < m_current_file_line;
+ default:
+ return false;
+ }
+ }
+
+private:
+ std::vector<FileSpec> m_file_stack;
+ State m_state;
+ FileSpec m_current_file;
+ uint32_t m_current_file_line;
+};
+
+} // anonymous namespace
+
+static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit,
+ AddMacroState &state, StreamString &stream) {
+ if (dm == nullptr)
+ return;
+
+ for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) {
+ const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i);
+ uint32_t line;
+
+ switch (entry.GetType()) {
+ case DebugMacroEntry::DEFINE:
+ if (state.IsValidEntry(entry.GetLineNumber()))
+ stream.Printf("#define %s\n", entry.GetMacroString().AsCString());
+ else
+ return;
+ break;
+ case DebugMacroEntry::UNDEF:
+ if (state.IsValidEntry(entry.GetLineNumber()))
+ stream.Printf("#undef %s\n", entry.GetMacroString().AsCString());
+ else
+ return;
+ break;
+ case DebugMacroEntry::START_FILE:
+ line = entry.GetLineNumber();
+ if (state.IsValidEntry(line))
+ state.StartFile(entry.GetFileSpec(comp_unit));
+ else
+ return;
+ break;
+ case DebugMacroEntry::END_FILE:
+ state.EndFile();
+ break;
+ case DebugMacroEntry::INDIRECT:
+ AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream);
+ break;
+ default:
+ // This is an unknown/invalid entry. Ignore.
+ break;
+ }
+ }
+}
+
+namespace {
+/// Allows checking if a token is contained in a given expression.
+class TokenVerifier {
+ /// The tokens we found in the expression.
+ llvm::StringSet<> m_tokens;
+
+public:
+ TokenVerifier(std::string body);
+ /// Returns true iff the given expression body contained a token with the
+ /// given content.
+ bool hasToken(llvm::StringRef token) const {
+ return m_tokens.find(token) != m_tokens.end();
+ }
+};
+} // namespace
+
+TokenVerifier::TokenVerifier(std::string body) {
+ using namespace clang;
+
+ // We only care about tokens and not their original source locations. If we
+ // move the whole expression to only be in one line we can simplify the
+ // following code that extracts the token contents.
+ std::replace(body.begin(), body.end(), '\n', ' ');
+ std::replace(body.begin(), body.end(), '\r', ' ');
+
+ FileSystemOptions file_opts;
+ FileManager file_mgr(file_opts,
+ FileSystem::Instance().GetVirtualFileSystem());
+
+ // Let's build the actual source code Clang needs and setup some utility
+ // objects.
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
+ new DiagnosticOptions());
+ DiagnosticsEngine diags(diag_ids, diags_opts);
+ clang::SourceManager SM(diags, file_mgr);
+ auto buf = llvm::MemoryBuffer::getMemBuffer(body);
+
+ FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get());
+
+ // Let's just enable the latest ObjC and C++ which should get most tokens
+ // right.
+ LangOptions Opts;
+ Opts.ObjC = true;
+ Opts.DollarIdents = true;
+ Opts.CPlusPlus17 = true;
+ Opts.LineComment = true;
+
+ Lexer lex(FID, buf.get(), SM, Opts);
+
+ Token token;
+ bool exit = false;
+ while (!exit) {
+ // Returns true if this is the last token we get from the lexer.
+ exit = lex.LexFromRawLexer(token);
+
+ // Extract the column number which we need to extract the token content.
+ // Our expression is just one line, so we don't need to handle any line
+ // numbers here.
+ bool invalid = false;
+ unsigned start = SM.getSpellingColumnNumber(token.getLocation(), &invalid);
+ if (invalid)
+ continue;
+ // Column numbers start at 1, but indexes in our string start at 0.
+ --start;
+
+ // Annotations don't have a length, so let's skip them.
+ if (token.isAnnotation())
+ continue;
+
+ // Extract the token string from our source code and store it.
+ std::string token_str = body.substr(start, token.getLength());
+ if (token_str.empty())
+ continue;
+ m_tokens.insert(token_str);
+ }
+}
+
+static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp,
+ StreamString &stream,
+ const std::string &expr,
+ lldb::LanguageType wrapping_language) {
+ TokenVerifier tokens(expr);
+
+ for (size_t i = 0; i < var_list_sp->GetSize(); i++) {
+ lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
+
+ ConstString var_name = var_sp->GetName();
+
+
+ // We can check for .block_descriptor w/o checking for langauge since this
+ // is not a valid identifier in either C or C++.
+ if (!var_name || var_name == ".block_descriptor")
+ continue;
+
+ 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))
+ continue;
+
+ if (var_name == "this" &&
+ wrapping_language == lldb::eLanguageTypeC_plus_plus)
+ continue;
+
+ stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
+ }
+}
+
+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 {
+ const char *target_specific_defines = "typedef signed char BOOL;\n";
+ std::string module_macros;
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64) {
+ target_specific_defines = "typedef bool BOOL;\n";
+ }
+ if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) {
+ if (lldb::PlatformSP platform_sp = target->GetPlatform()) {
+ static ConstString g_platform_ios_simulator("ios-simulator");
+ if (platform_sp->GetPluginName() == g_platform_ios_simulator) {
+ target_specific_defines = "typedef bool BOOL;\n";
+ }
+ }
+ }
+
+ if (ClangModulesDeclVendor *decl_vendor =
+ target->GetClangModulesDeclVendor()) {
+ ClangPersistentVariables *persistent_vars =
+ llvm::cast<ClangPersistentVariables>(
+ target->GetPersistentExpressionStateForLanguage(
+ lldb::eLanguageTypeC));
+ const ClangModulesDeclVendor::ModuleVector &hand_imported_modules =
+ persistent_vars->GetHandLoadedClangModules();
+ ClangModulesDeclVendor::ModuleVector modules_for_macros;
+
+ for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) {
+ modules_for_macros.push_back(module);
+ }
+
+ if (target->GetEnableAutoImportClangModules()) {
+ if (StackFrame *frame = exe_ctx.GetFramePtr()) {
+ if (Block *block = frame->GetFrameBlock()) {
+ SymbolContext sc;
+
+ block->CalculateSymbolContext(&sc);
+
+ if (sc.comp_unit) {
+ StreamString error_stream;
+
+ decl_vendor->AddModulesForCompileUnit(
+ *sc.comp_unit, modules_for_macros, error_stream);
+ }
+ }
+ }
+ }
+
+ decl_vendor->ForEachMacro(
+ modules_for_macros,
+ [&module_macros](const std::string &expansion) -> bool {
+ module_macros.append(expansion);
+ module_macros.append("\n");
+ return false;
+ });
+ }
+ }
+
+ StreamString debug_macros_stream;
+ StreamString lldb_local_var_decls;
+ if (StackFrame *frame = exe_ctx.GetFramePtr()) {
+ const SymbolContext &sc = frame->GetSymbolContext(
+ lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry);
+
+ if (sc.comp_unit && sc.line_entry.IsValid()) {
+ DebugMacros *dm = sc.comp_unit->GetDebugMacros();
+ if (dm) {
+ AddMacroState state(sc.line_entry.file, sc.line_entry.line);
+ AddMacros(dm, sc.comp_unit, state, debug_macros_stream);
+ }
+ }
+
+ if (add_locals)
+ if (target->GetInjectLocalVariables(&exe_ctx)) {
+ 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);
+ }
+ }
+
+ 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;
+ for (const std::string &module : modules) {
+ module_imports.append("@import ");
+ module_imports.append(module);
+ module_imports.append(";\n");
+ }
+
+ StreamString wrap_stream;
+
+ wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(),
+ debug_macros_stream.GetData(), g_expression_prefix,
+ target_specific_defines, m_prefix.c_str());
+
+ // 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(c_start_marker);
+ tagged_body.append(m_body);
+ tagged_body.append(c_end_marker);
+ break;
+ }
+ switch (wrapping_language) {
+ default:
+ break;
+ case lldb::eLanguageTypeC:
+ wrap_stream.Printf("%s"
+ "void \n"
+ "%s(void *$__lldb_arg) \n"
+ "{ \n"
+ " %s; \n"
+ "%s"
+ "} \n",
+ module_imports.c_str(), m_name.c_str(),
+ lldb_local_var_decls.GetData(), tagged_body.c_str());
+ break;
+ case lldb::eLanguageTypeC_plus_plus:
+ wrap_stream.Printf("%s"
+ "void \n"
+ "$__lldb_class::%s(void *$__lldb_arg) \n"
+ "{ \n"
+ " %s; \n"
+ "%s"
+ "} \n",
+ 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());
+ }
+ break;
+ }
+
+ text = wrap_stream.GetString();
+ } else {
+ text.append(m_body);
+ }
+
+ return true;
+}
+
+bool ClangExpressionSourceCode::GetOriginalBodyBounds(
+ std::string transformed_text, lldb::LanguageType wrapping_language,
+ size_t &start_loc, size_t &end_loc) {
+ const char *start_marker;
+ const char *end_marker;
+
+ switch (wrapping_language) {
+ default:
+ return false;
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeObjC:
+ start_marker = c_start_marker;
+ end_marker = c_end_marker;
+ break;
+ }
+
+ start_loc = transformed_text.find(start_marker);
+ if (start_loc == std::string::npos)
+ return false;
+ start_loc += strlen(start_marker);
+ end_loc = transformed_text.find(end_marker);
+ return end_loc != std::string::npos;
+}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
new file mode 100644
index 000000000000..894290295837
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
@@ -0,0 +1,71 @@
+//===-- ClangExpressionSourceCode.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 liblldb_ClangExpressionSourceCode_h
+#define liblldb_ClangExpressionSourceCode_h
+
+#include "lldb/Expression/Expression.h"
+#include "lldb/Expression/ExpressionSourceCode.h"
+#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <string>
+
+namespace lldb_private {
+
+class ExecutionContext;
+
+class ClangExpressionSourceCode : public ExpressionSourceCode {
+public:
+ static const char *g_expression_prefix;
+
+ static ClangExpressionSourceCode *CreateWrapped(const char *prefix,
+ const char *body) {
+ return new ClangExpressionSourceCode("$__lldb_expr", prefix, body, true);
+ }
+
+ uint32_t GetNumBodyLines();
+
+ /// 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
+ /// expression source code.
+ /// \param force_add_all_locals True iff all local variables should be
+ /// injected even if they are not used in the expression.
+ /// \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 force_add_all_locals,
+ llvm::ArrayRef<std::string> modules) const;
+
+ // Given a string returned by GetText, find the beginning and end of the body
+ // passed to CreateWrapped. Return true if the bounds could be found. This
+ // will also work on text with FixItHints applied.
+ static bool GetOriginalBodyBounds(std::string transformed_text,
+ lldb::LanguageType wrapping_language,
+ size_t &start_loc, size_t &end_loc);
+
+protected:
+ ClangExpressionSourceCode(const char *name, const char *prefix, const char *body,
+ bool wrap) :
+ ExpressionSourceCode(name, prefix, body, wrap) {}
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
index 624cbf2a1a4f..b5a2c80b5349 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp
@@ -1,9 +1,8 @@
//===-- ClangExpressionVariable.cpp -----------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -32,7 +31,7 @@ ClangExpressionVariable::ClangExpressionVariable(
}
ClangExpressionVariable::ClangExpressionVariable(
- ExecutionContextScope *exe_scope, Value &value, const ConstString &name,
+ ExecutionContextScope *exe_scope, Value &value, ConstString name,
uint16_t flags)
: ExpressionVariable(LLVMCastKind::eKindClang), m_parser_vars(),
m_jit_vars() {
@@ -49,7 +48,7 @@ ClangExpressionVariable::ClangExpressionVariable(
}
ClangExpressionVariable::ClangExpressionVariable(
- ExecutionContextScope *exe_scope, const ConstString &name,
+ ExecutionContextScope *exe_scope, ConstString name,
const TypeFromUser &user_type, lldb::ByteOrder byte_order,
uint32_t addr_byte_size)
: ExpressionVariable(LLVMCastKind::eKindClang), m_parser_vars(),
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
index 6886f0940adb..eb7f74f20a20 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h
@@ -1,9 +1,8 @@
//===-- ClangExpressionVariable.h -------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -35,8 +34,7 @@ namespace lldb_private {
class ValueObjectConstResult;
-//----------------------------------------------------------------------
-/// @class ClangExpressionVariable ClangExpressionVariable.h
+/// \class ClangExpressionVariable ClangExpressionVariable.h
/// "lldb/Expression/ClangExpressionVariable.h" Encapsulates one variable for
/// the expression parser.
///
@@ -56,36 +54,31 @@ class ValueObjectConstResult;
///
/// This class supports all of these use cases using simple type polymorphism,
/// and provides necessary support methods. Its interface is RTTI-neutral.
-//----------------------------------------------------------------------
class ClangExpressionVariable : public ExpressionVariable {
public:
ClangExpressionVariable(ExecutionContextScope *exe_scope,
lldb::ByteOrder byte_order, uint32_t addr_byte_size);
ClangExpressionVariable(ExecutionContextScope *exe_scope, Value &value,
- const ConstString &name, uint16_t flags = EVNone);
+ ConstString name, uint16_t flags = EVNone);
ClangExpressionVariable(const lldb::ValueObjectSP &valobj_sp);
ClangExpressionVariable(ExecutionContextScope *exe_scope,
- const ConstString &name,
+ ConstString name,
const TypeFromUser &user_type,
lldb::ByteOrder byte_order, uint32_t addr_byte_size);
- //----------------------------------------------------------------------
/// Utility functions for dealing with ExpressionVariableLists in Clang-
/// specific ways
- //----------------------------------------------------------------------
- //----------------------------------------------------------------------
/// Finds a variable by NamedDecl in the list.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the requested variable.
///
- /// @return
+ /// \return
/// The variable requested, or NULL if that variable is not in the list.
- //----------------------------------------------------------------------
static ClangExpressionVariable *
FindVariableInList(ExpressionVariableList &list, const clang::NamedDecl *decl,
uint64_t parser_id) {
@@ -105,31 +98,27 @@ public:
return nullptr;
}
- //----------------------------------------------------------------------
/// If the variable contains its own data, make a Value point at it. If \a
/// exe_ctx in not NULL, the value will be resolved in with that execution
/// context.
///
- /// @param[in] value
+ /// \param[in] value
/// The value to point at the data.
///
- /// @param[in] exe_ctx
+ /// \param[in] exe_ctx
/// The execution context to use to resolve \a value.
///
- /// @return
+ /// \return
/// True on success; false otherwise (in particular, if this variable
/// does not contain its own data).
- //----------------------------------------------------------------------
bool PointValueAtData(Value &value, ExecutionContext *exe_ctx);
- //----------------------------------------------------------------------
/// The following values should not live beyond parsing
- //----------------------------------------------------------------------
class ParserVars {
public:
ParserVars()
- : m_parser_type(), m_named_decl(NULL), m_llvm_value(NULL),
- m_lldb_value(), m_lldb_var(), m_lldb_sym(NULL) {}
+ : m_parser_type(), 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
@@ -149,34 +138,26 @@ private:
ParserVarMap m_parser_vars;
public:
- //----------------------------------------------------------------------
/// Make this variable usable by the parser by allocating space for parser-
/// specific variables
- //----------------------------------------------------------------------
void EnableParserVars(uint64_t parser_id) {
m_parser_vars.insert(std::make_pair(parser_id, ParserVars()));
}
- //----------------------------------------------------------------------
/// Deallocate parser-specific variables
- //----------------------------------------------------------------------
void DisableParserVars(uint64_t parser_id) { m_parser_vars.erase(parser_id); }
- //----------------------------------------------------------------------
/// Access parser-specific variables
- //----------------------------------------------------------------------
ParserVars *GetParserVars(uint64_t parser_id) {
ParserVarMap::iterator i = m_parser_vars.find(parser_id);
if (i == m_parser_vars.end())
- return NULL;
+ return nullptr;
else
return &i->second;
}
- //----------------------------------------------------------------------
/// The following values are valid if the variable is used by JIT code
- //----------------------------------------------------------------------
struct JITVars {
JITVars() : m_alignment(0), m_size(0), m_offset(0) {}
@@ -192,40 +173,32 @@ private:
JITVarMap m_jit_vars;
public:
- //----------------------------------------------------------------------
/// Make this variable usable for materializing for the JIT by allocating
/// space for JIT-specific variables
- //----------------------------------------------------------------------
void EnableJITVars(uint64_t parser_id) {
m_jit_vars.insert(std::make_pair(parser_id, JITVars()));
}
- //----------------------------------------------------------------------
/// Deallocate JIT-specific variables
- //----------------------------------------------------------------------
void DisableJITVars(uint64_t parser_id) { m_jit_vars.erase(parser_id); }
JITVars *GetJITVars(uint64_t parser_id) {
JITVarMap::iterator i = m_jit_vars.find(parser_id);
if (i == m_jit_vars.end())
- return NULL;
+ return nullptr;
else
return &i->second;
}
TypeFromUser GetTypeFromUser();
- //------------------------------------------------------------------
// llvm casting support
- //------------------------------------------------------------------
static bool classof(const ExpressionVariable *ev) {
return ev->getKind() == ExpressionVariable::eKindClang;
}
- //----------------------------------------------------------------------
/// Members
- //----------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN(ClangExpressionVariable);
};
diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
index 8ec9ff2235f5..eabc96aa8e51 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
@@ -1,9 +1,8 @@
//===-- ClangFunctionCaller.cpp ---------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -43,9 +42,7 @@
using namespace lldb_private;
-//----------------------------------------------------------------------
// ClangFunctionCaller constructor
-//----------------------------------------------------------------------
ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope,
const CompilerType &return_type,
const Address &functionAddress,
@@ -59,9 +56,7 @@ ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope,
assert(m_jit_process_wp.lock());
}
-//----------------------------------------------------------------------
// Destructor
-//----------------------------------------------------------------------
ClangFunctionCaller::~ClangFunctionCaller() {}
unsigned
diff --git a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
index 9d933bfa6095..24f6f2eb91b3 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h
@@ -1,9 +1,8 @@
//===-- ClangFunctionCaller.h -----------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -25,8 +24,7 @@ namespace lldb_private {
class ASTStructExtractor;
class ClangExpressionParser;
-//----------------------------------------------------------------------
-/// @class ClangFunctionCaller ClangFunctionCaller.h
+/// \class ClangFunctionCaller ClangFunctionCaller.h
/// "lldb/Expression/ClangFunctionCaller.h" Encapsulates a function that can
/// be called.
///
@@ -58,30 +56,30 @@ class ClangExpressionParser;
///
/// Any of the methods that take arg_addr_ptr can be passed NULL, and the
/// argument space will be managed for you.
-//----------------------------------------------------------------------
class ClangFunctionCaller : public FunctionCaller {
friend class ASTStructExtractor;
+ /// LLVM-style RTTI support.
+ static bool classof(const Expression *E) {
+ return E->getKind() == eKindClangFunctionCaller;
+ }
+
class ClangFunctionCallerHelper : public ClangExpressionHelper {
public:
ClangFunctionCallerHelper(ClangFunctionCaller &owner) : m_owner(owner) {}
~ClangFunctionCallerHelper() override = default;
- //------------------------------------------------------------------
/// Return the object that the parser should use when resolving external
/// values. May be NULL if everything should be self-contained.
- //------------------------------------------------------------------
- ClangExpressionDeclMap *DeclMap() override { return NULL; }
+ ClangExpressionDeclMap *DeclMap() override { return nullptr; }
- //------------------------------------------------------------------
/// Return the object that the parser should allow to access ASTs. May be
/// NULL if the ASTs do not need to be transformed.
///
- /// @param[in] passthrough
+ /// \param[in] passthrough
/// The ASTConsumer that the returned transformer should send
/// the ASTs to after transformation.
- //------------------------------------------------------------------
clang::ASTConsumer *
ASTTransformer(clang::ASTConsumer *passthrough) override;
@@ -94,27 +92,25 @@ class ClangFunctionCaller : public FunctionCaller {
};
public:
- //------------------------------------------------------------------
/// Constructor
///
- /// @param[in] exe_scope
+ /// \param[in] exe_scope
/// An execution context scope that gets us at least a target and
/// process.
///
- /// @param[in] ast_context
+ /// \param[in] ast_context
/// The AST context to evaluate argument types in.
///
- /// @param[in] return_qualtype
+ /// \param[in] return_qualtype
/// An opaque Clang QualType for the function result. Should be
/// defined in ast_context.
///
- /// @param[in] function_address
+ /// \param[in] function_address
/// The address of the function to call.
///
- /// @param[in] arg_value_list
+ /// \param[in] arg_value_list
/// The default values to use when calling this function. Can
/// be overridden using WriteFunctionArguments().
- //------------------------------------------------------------------
ClangFunctionCaller(ExecutionContextScope &exe_scope,
const CompilerType &return_type,
const Address &function_address,
@@ -122,20 +118,18 @@ public:
~ClangFunctionCaller() override;
- //------------------------------------------------------------------
/// Compile the wrapper function
///
- /// @param[in] thread_to_use_sp
+ /// \param[in] thread_to_use_sp
/// Compilation might end up calling functions. Pass in the thread you
/// want the compilation to use. If you pass in an empty ThreadSP it will
/// use the currently selected thread.
///
- /// @param[in] diagnostic_manager
+ /// \param[in] diagnostic_manager
/// The diagnostic manager to report parser errors to.
///
- /// @return
+ /// \return
/// The number of errors.
- //------------------------------------------------------------------
unsigned CompileFunction(lldb::ThreadSP thread_to_use_sp,
DiagnosticManager &diagnostic_manager) override;
@@ -147,9 +141,7 @@ protected:
const char *GetWrapperStructName() { return m_wrapper_struct_name.c_str(); }
private:
- //------------------------------------------------------------------
// For ClangFunctionCaller only
- //------------------------------------------------------------------
// Note: the parser needs to be destructed before the execution unit, so
// declare the execution unit first.
diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
index 44a13353818a..65c547391831 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangHost.cpp
@@ -1,9 +1,8 @@
//===-- ClangHost.cpp -------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -17,11 +16,9 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Threading.h"
+#include "lldb/Host/Config.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
-#if !defined(_WIN32)
-#include "lldb/Host/posix/HostInfoPosix.h"
-#endif
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Log.h"
@@ -29,18 +26,6 @@
using namespace lldb_private;
-#if defined(_WIN32)
-static bool ComputeClangDirectory(FileSpec &file_spec) { return false; }
-#else
-static bool DefaultComputeClangDirectory(FileSpec &file_spec) {
- return HostInfoPosix::ComputePathRelativeToLibrary(
- file_spec, (llvm::Twine("/lib") + CLANG_LIBDIR_SUFFIX + "/clang/" +
- CLANG_VERSION_STRING)
- .str());
-}
-
-#if defined(__APPLE__)
-
static bool VerifyClangPath(const llvm::Twine &clang_path) {
if (FileSystem::Instance().IsDirectory(clang_path))
return true;
@@ -52,8 +37,55 @@ static bool VerifyClangPath(const llvm::Twine &clang_path) {
return false;
}
-bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec,
+///
+/// This will compute the clang resource directory assuming that clang was
+/// installed with the same prefix as lldb.
+///
+/// If verify is true, the first candidate resource directory will be returned.
+/// This mode is only used for testing.
+///
+static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
+ FileSpec &file_spec,
+ bool verify) {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ std::string raw_path = lldb_shlib_spec.GetPath();
+ llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path);
+
+ static const llvm::StringRef kResourceDirSuffixes[] = {
+ // LLVM.org's build of LLDB uses the clang resource directory placed
+ // in $install_dir/lib{,64}/clang/$clang_version.
+ "lib" CLANG_LIBDIR_SUFFIX "/clang/" CLANG_VERSION_STRING,
+ // swift-lldb uses the clang resource directory copied from swift, which
+ // by default is placed in $install_dir/lib{,64}/lldb/clang. LLDB places
+ // it there, so we use LLDB_LIBDIR_SUFFIX.
+ "lib" LLDB_LIBDIR_SUFFIX "/lldb/clang",
+ };
+
+ for (const auto &Suffix : kResourceDirSuffixes) {
+ llvm::SmallString<256> clang_dir(parent_dir);
+ llvm::SmallString<32> relative_path(Suffix);
+ llvm::sys::path::native(relative_path);
+ llvm::sys::path::append(clang_dir, relative_path);
+ if (!verify || VerifyClangPath(clang_dir)) {
+ if (log)
+ log->Printf("DefaultComputeClangResourceDir: Setting ClangResourceDir "
+ "to \"%s\", verify = %s",
+ clang_dir.str().str().c_str(), verify ? "true" : "false");
+ file_spec.GetDirectory().SetString(clang_dir);
+ FileSystem::Instance().Resolve(file_spec);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
FileSpec &file_spec, bool verify) {
+#if !defined(__APPLE__)
+ return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,
+ verify);
+#else
std::string raw_path = lldb_shlib_spec.GetPath();
auto rev_it = llvm::sys::path::rbegin(raw_path);
@@ -66,8 +98,10 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec,
++rev_it;
}
+ // We found a non-framework build of LLDB
if (rev_it == r_end)
- return DefaultComputeClangDirectory(file_spec);
+ return DefaultComputeClangResourceDirectory(lldb_shlib_spec, file_spec,
+ verify);
// Inside Xcode and in Xcode toolchains LLDB is always in lockstep
// with the Swift compiler, so it can reuse its Clang resource
@@ -84,7 +118,7 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec,
"Developer/Toolchains/XcodeDefault.xctoolchain",
swift_clang_resource_dir);
if (!verify || VerifyClangPath(clang_path)) {
- file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native);
+ file_spec.GetDirectory().SetString(clang_path.c_str());
FileSystem::Instance().Resolve(file_spec);
return true;
}
@@ -99,7 +133,7 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec,
raw_path.resize(parent - r_end);
llvm::sys::path::append(clang_path, raw_path, swift_clang_resource_dir);
if (!verify || VerifyClangPath(clang_path)) {
- file_spec.SetFile(clang_path.c_str(), FileSpec::Style::native);
+ file_spec.GetDirectory().SetString(clang_path.c_str());
FileSystem::Instance().Resolve(file_spec);
return true;
}
@@ -112,30 +146,19 @@ bool lldb_private::ComputeClangDirectory(FileSpec &lldb_shlib_spec,
// Fall back to the Clang resource directory inside the framework.
raw_path.append("LLDB.framework/Resources/Clang");
- file_spec.SetFile(raw_path.c_str(), FileSpec::Style::native);
+ file_spec.GetDirectory().SetString(raw_path.c_str());
FileSystem::Instance().Resolve(file_spec);
return true;
-}
-
-static bool ComputeClangDirectory(FileSpec &file_spec) {
- if (FileSpec lldb_file_spec = HostInfo::GetShlibDir())
- return ComputeClangDirectory(lldb_file_spec, file_spec, true);
- return false;
-}
-#else // __APPLE__
-
-// All non-Apple posix systems.
-static bool ComputeClangDirectory(FileSpec &file_spec) {
- return DefaultComputeClangDirectory(file_spec);
-}
#endif // __APPLE__
-#endif // _WIN32
+}
FileSpec lldb_private::GetClangResourceDir() {
static FileSpec g_cached_resource_dir;
static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, []() {
- ::ComputeClangDirectory(g_cached_resource_dir);
+ if (FileSpec lldb_file_spec = HostInfo::GetShlibDir())
+ ComputeClangResourceDirectory(lldb_file_spec, g_cached_resource_dir,
+ true);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf("GetClangResourceDir() => '%s'",
diff --git a/source/Plugins/ExpressionParser/Clang/ClangHost.h b/source/Plugins/ExpressionParser/Clang/ClangHost.h
index 4fe423adb1a5..9d49188178cd 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangHost.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangHost.h
@@ -1,9 +1,8 @@
//===-- ClangHost.h ---------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -14,10 +13,8 @@ namespace lldb_private {
class FileSpec;
-#if defined(__APPLE__)
-bool ComputeClangDirectory(FileSpec &lldb_shlib_spec, FileSpec &file_spec,
- bool verify);
-#endif
+bool ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec,
+ FileSpec &file_spec, bool verify);
FileSpec GetClangResourceDir();
diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index ced21dfe0dda..4a220790e50d 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -1,9 +1,8 @@
//===-- ClangModulesDeclVendor.cpp ------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -23,15 +22,18 @@
#include "ClangHost.h"
#include "ClangModulesDeclVendor.h"
+#include "ModuleDependencyCollector.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SourceModule.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Reproducer.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
@@ -70,13 +72,13 @@ public:
~ClangModulesDeclVendorImpl() override = default;
- bool AddModule(ModulePath &path, ModuleVector *exported_modules,
+ bool AddModule(const SourceModule &module, ModuleVector *exported_modules,
Stream &error_stream) override;
bool AddModulesForCompileUnit(CompileUnit &cu, ModuleVector &exported_modules,
Stream &error_stream) override;
- uint32_t FindDecls(const ConstString &name, bool append, uint32_t max_matches,
+ uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches,
std::vector<clang::NamedDecl *> &decls) override;
void ForEachMacro(const ModuleVector &modules,
@@ -183,7 +185,7 @@ void ClangModulesDeclVendorImpl::ReportModuleExports(
}
}
-bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
+bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module,
ModuleVector *exported_modules,
Stream &error_stream) {
// Fail early.
@@ -198,7 +200,7 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
std::vector<ConstString> imported_module;
- for (ConstString path_component : path) {
+ for (ConstString path_component : module.path) {
imported_module.push_back(path_component);
}
@@ -213,11 +215,42 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
}
}
- if (!m_compiler_instance->getPreprocessor()
- .getHeaderSearchInfo()
- .lookupModule(path[0].GetStringRef())) {
+ clang::HeaderSearch &HS =
+ m_compiler_instance->getPreprocessor().getHeaderSearchInfo();
+
+ if (module.search_path) {
+ auto path_begin = llvm::sys::path::begin(module.search_path.GetStringRef());
+ auto path_end = llvm::sys::path::end(module.search_path.GetStringRef());
+ auto sysroot_begin = llvm::sys::path::begin(module.sysroot.GetStringRef());
+ auto sysroot_end = llvm::sys::path::end(module.sysroot.GetStringRef());
+ // FIXME: Use C++14 std::equal(it, it, it, it) variant once it's available.
+ bool is_system_module = (std::distance(path_begin, path_end) >=
+ std::distance(sysroot_begin, sysroot_end)) &&
+ std::equal(sysroot_begin, sysroot_end, path_begin);
+ // No need to inject search paths to modules in the sysroot.
+ if (!is_system_module) {
+ auto error = [&]() {
+ error_stream.Printf("error: No module map file in %s\n",
+ module.search_path.AsCString());
+ return false;
+ };
+
+ bool is_system = true;
+ bool is_framework = false;
+ auto *dir =
+ HS.getFileMgr().getDirectory(module.search_path.GetStringRef());
+ if (!dir)
+ return error();
+ auto *file = HS.lookupModuleMapFile(dir, is_framework);
+ if (!file)
+ return error();
+ if (!HS.loadModuleMapFile(file, is_system))
+ return error();
+ }
+ }
+ if (!HS.lookupModule(module.path.front().GetStringRef())) {
error_stream.Printf("error: Header search couldn't locate module %s\n",
- path[0].AsCString());
+ module.path.front().AsCString());
return false;
}
@@ -229,7 +262,7 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
clang::SourceManager &source_manager =
m_compiler_instance->getASTContext().getSourceManager();
- for (ConstString path_component : path) {
+ for (ConstString path_component : module.path) {
clang_path.push_back(std::make_pair(
&m_compiler_instance->getASTContext().Idents.get(
path_component.GetStringRef()),
@@ -249,19 +282,18 @@ bool ClangModulesDeclVendorImpl::AddModule(ModulePath &path,
if (!top_level_module) {
diagnostic_consumer->DumpDiagnostics(error_stream);
error_stream.Printf("error: Couldn't load top-level module %s\n",
- path[0].AsCString());
+ module.path.front().AsCString());
return false;
}
clang::Module *submodule = top_level_module;
- for (size_t ci = 1; ci < path.size(); ++ci) {
- llvm::StringRef component = path[ci].GetStringRef();
- submodule = submodule->findSubmodule(component.str());
+ for (auto &component : llvm::ArrayRef<ConstString>(module.path).drop_front()) {
+ submodule = submodule->findSubmodule(component.GetStringRef());
if (!submodule) {
diagnostic_consumer->DumpDiagnostics(error_stream);
error_stream.Printf("error: Couldn't load submodule %s\n",
- component.str().c_str());
+ component.GetCString());
return false;
}
}
@@ -288,12 +320,16 @@ bool ClangModulesDeclVendor::LanguageSupportsClangModules(
switch (language) {
default:
return false;
- // C++ and friends to be added
case lldb::LanguageType::eLanguageTypeC:
case lldb::LanguageType::eLanguageTypeC11:
case lldb::LanguageType::eLanguageTypeC89:
case lldb::LanguageType::eLanguageTypeC99:
+ case lldb::LanguageType::eLanguageTypeC_plus_plus:
+ case lldb::LanguageType::eLanguageTypeC_plus_plus_03:
+ case lldb::LanguageType::eLanguageTypeC_plus_plus_11:
+ case lldb::LanguageType::eLanguageTypeC_plus_plus_14:
case lldb::LanguageType::eLanguageTypeObjC:
+ case lldb::LanguageType::eLanguageTypeObjC_plus_plus:
return true;
}
}
@@ -302,28 +338,17 @@ bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules,
Stream &error_stream) {
if (LanguageSupportsClangModules(cu.GetLanguage())) {
- std::vector<ConstString> imported_modules = cu.GetImportedModules();
-
- for (ConstString imported_module : imported_modules) {
- std::vector<ConstString> path;
-
- path.push_back(imported_module);
-
- if (!AddModule(path, &exported_modules, error_stream)) {
+ for (auto &imported_module : cu.GetImportedModules())
+ if (!AddModule(imported_module, &exported_modules, error_stream))
return false;
- }
- }
-
- return true;
}
-
return true;
}
// ClangImporter::lookupValue
uint32_t
-ClangModulesDeclVendorImpl::FindDecls(const ConstString &name, bool append,
+ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append,
uint32_t max_matches,
std::vector<clang::NamedDecl *> &decls) {
if (!m_enabled) {
@@ -583,7 +608,7 @@ ClangModulesDeclVendor::Create(Target &target) {
compiler_invocation_arguments.push_back(module_cache_argument);
}
- FileSpecList &module_search_paths = target.GetClangModuleSearchPaths();
+ FileSpecList module_search_paths = target.GetClangModuleSearchPaths();
for (size_t spi = 0, spe = module_search_paths.GetSize(); spi < spe; ++spi) {
const FileSpec &search_path = module_search_paths.GetFileSpecAtIndex(spi);
@@ -610,9 +635,13 @@ ClangModulesDeclVendor::Create(Target &target) {
std::vector<const char *> compiler_invocation_argument_cstrs;
compiler_invocation_argument_cstrs.reserve(
compiler_invocation_arguments.size());
- for (const std::string &arg : compiler_invocation_arguments) {
+ for (const std::string &arg : compiler_invocation_arguments)
compiler_invocation_argument_cstrs.push_back(arg.c_str());
- }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+ LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}",
+ llvm::make_range(compiler_invocation_arguments.begin(),
+ compiler_invocation_arguments.end()));
std::shared_ptr<clang::CompilerInvocation> invocation =
clang::createInvocationFromCommandLine(compiler_invocation_argument_cstrs,
@@ -632,6 +661,20 @@ ClangModulesDeclVendor::Create(Target &target) {
std::unique_ptr<clang::CompilerInstance> instance(
new clang::CompilerInstance);
+ // When capturing a reproducer, hook up the file collector with clang to
+ // collector modules and headers.
+ if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) {
+ repro::FileProvider &fp = g->GetOrCreate<repro::FileProvider>();
+ instance->setModuleDepCollector(
+ std::make_shared<ModuleDependencyCollectorAdaptor>(
+ fp.GetFileCollector()));
+ clang::DependencyOutputOptions &opts = instance->getDependencyOutputOpts();
+ opts.IncludeSystemHeaders = true;
+ opts.IncludeModuleFiles = true;
+ }
+
+ // Make sure clang uses the same VFS as LLDB.
+ instance->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
instance->setDiagnostics(diagnostics_engine.get());
instance->setInvocation(invocation);
diff --git a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
index 23769ccfb0c0..d5c8757bdcd0 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h
@@ -1,9 +1,8 @@
//===-- ClangModulesDeclVendor.h --------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -12,6 +11,7 @@
#include "lldb/Core/ClangForward.h"
#include "lldb/Symbol/DeclVendor.h"
+#include "lldb/Symbol/SourceModule.h"
#include "lldb/Target/Platform.h"
#include <set>
@@ -21,9 +21,7 @@ namespace lldb_private {
class ClangModulesDeclVendor : public DeclVendor {
public:
- //------------------------------------------------------------------
// Constructors and Destructors
- //------------------------------------------------------------------
ClangModulesDeclVendor();
~ClangModulesDeclVendor() override;
@@ -34,84 +32,77 @@ public:
typedef uintptr_t ModuleID;
typedef std::vector<ModuleID> ModuleVector;
- //------------------------------------------------------------------
/// Add a module to the list of modules to search.
///
- /// @param[in] path
+ /// \param[in] module
/// The path to the exact module to be loaded. E.g., if the desired
/// module is std.io, then this should be { "std", "io" }.
///
- /// @param[in] exported_modules
+ /// \param[in] exported_modules
/// If non-NULL, a pointer to a vector to populate with the ID of every
/// module that is re-exported by the specified module.
///
- /// @param[in] error_stream
+ /// \param[in] error_stream
/// A stream to populate with the output of the Clang parser when
/// it tries to load the module.
///
- /// @return
+ /// \return
/// True if the module could be loaded; false if not. If the
/// compiler encountered a fatal error during a previous module
/// load, then this will always return false for this ModuleImporter.
- //------------------------------------------------------------------
- virtual bool AddModule(ModulePath &path, ModuleVector *exported_modules,
+ virtual bool AddModule(const SourceModule &module,
+ ModuleVector *exported_modules,
Stream &error_stream) = 0;
- //------------------------------------------------------------------
/// Add all modules referred to in a given compilation unit to the list
/// of modules to search.
///
- /// @param[in] cu
+ /// \param[in] cu
/// The compilation unit to scan for imported modules.
///
- /// @param[in] exported_modules
+ /// \param[in] exported_modules
/// A vector to populate with the ID of each module loaded (directly
/// and via re-exports) in this way.
///
- /// @param[in] error_stream
+ /// \param[in] error_stream
/// A stream to populate with the output of the Clang parser when
/// it tries to load the modules.
///
- /// @return
+ /// \return
/// True if all modules referred to by the compilation unit could be
/// loaded; false if one could not be loaded. If the compiler
/// encountered a fatal error during a previous module
/// load, then this will always return false for this ModuleImporter.
- //------------------------------------------------------------------
virtual bool AddModulesForCompileUnit(CompileUnit &cu,
ModuleVector &exported_modules,
Stream &error_stream) = 0;
- //------------------------------------------------------------------
/// Enumerate all the macros that are defined by a given set of modules
/// that are already imported.
///
- /// @param[in] modules
+ /// \param[in] modules
/// The unique IDs for all modules to query. Later modules have higher
/// priority, just as if you @imported them in that order. This matters
/// if module A #defines a macro and module B #undefs it.
///
- /// @param[in] handler
+ /// \param[in] handler
/// A function to call with the text of each #define (including the
/// #define directive). #undef directives are not included; we simply
/// elide any corresponding #define. If this function returns true,
/// we stop the iteration immediately.
- //------------------------------------------------------------------
virtual void
ForEachMacro(const ModuleVector &modules,
std::function<bool(const std::string &)> handler) = 0;
- //------------------------------------------------------------------
/// Query whether Clang supports modules for a particular language.
/// LLDB uses this to decide whether to try to find the modules loaded
- /// by a gaiven compile unit.
+ /// by a given compile unit.
///
- /// @param[in] language
+ /// \param[in] language
/// The language to query for.
///
- /// @return
+ /// \return
/// True if Clang has modules for the given language.
- //------------------------------------------------------------------
static bool LanguageSupportsClangModules(lldb::LanguageType language);
};
diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
index bb73d55a9a41..742a14992dc9 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp
@@ -1,15 +1,15 @@
//===-- ClangPersistentVariables.cpp ----------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 "ClangPersistentVariables.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"
@@ -32,7 +32,7 @@ ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable(
}
ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable(
- ExecutionContextScope *exe_scope, const ConstString &name,
+ ExecutionContextScope *exe_scope, ConstString name,
const CompilerType &compiler_type, lldb::ByteOrder byte_order,
uint32_t addr_byte_size) {
return AddNewlyConstructedVariable(new ClangExpressionVariable(
@@ -49,11 +49,26 @@ void ClangPersistentVariables::RemovePersistentVariable(
return;
name++;
- if (strtoul(name, NULL, 0) == m_next_persistent_variable_id - 1)
+ if (strtoul(name, nullptr, 0) == m_next_persistent_variable_id - 1)
m_next_persistent_variable_id--;
}
-void ClangPersistentVariables::RegisterPersistentDecl(const ConstString &name,
+llvm::Optional<CompilerType>
+ClangPersistentVariables::GetCompilerTypeFromPersistentDecl(
+ ConstString type_name) {
+ CompilerType compiler_type;
+ if (clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>(
+ GetPersistentDecl(type_name))) {
+ compiler_type.SetCompilerType(
+ ClangASTContext::GetASTContext(&tdecl->getASTContext()),
+ reinterpret_cast<lldb::opaque_compiler_type_t>(
+ const_cast<clang::Type *>(tdecl->getTypeForDecl())));
+ return compiler_type;
+ }
+ return llvm::None;
+}
+
+void ClangPersistentVariables::RegisterPersistentDecl(ConstString name,
clang::NamedDecl *decl) {
m_persistent_decls.insert(
std::pair<const char *, clang::NamedDecl *>(name.GetCString(), decl));
@@ -68,12 +83,12 @@ void ClangPersistentVariables::RegisterPersistentDecl(const ConstString &name,
}
clang::NamedDecl *
-ClangPersistentVariables::GetPersistentDecl(const ConstString &name) {
+ClangPersistentVariables::GetPersistentDecl(ConstString name) {
PersistentDeclMap::const_iterator i =
m_persistent_decls.find(name.GetCString());
if (i == m_persistent_decls.end())
- return NULL;
+ return nullptr;
else
return i->second;
}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
index c4438c7e2203..b39f89ad7eef 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h
@@ -1,9 +1,8 @@
//===-- ClangPersistentVariables.h ------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -19,24 +18,20 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ClangPersistentVariables ClangPersistentVariables.h
+/// \class ClangPersistentVariables ClangPersistentVariables.h
/// "lldb/Expression/ClangPersistentVariables.h" Manages persistent values
/// that need to be preserved between expression invocations.
///
/// A list of variables that can be accessed and updated by any expression. See
/// ClangPersistentVariable for more discussion. Also provides an increasing,
/// 0-based counter for naming result variables.
-//----------------------------------------------------------------------
class ClangPersistentVariables : public PersistentExpressionState {
public:
ClangPersistentVariables();
~ClangPersistentVariables() override = default;
- //------------------------------------------------------------------
// llvm casting support
- //------------------------------------------------------------------
static bool classof(const PersistentExpressionState *pv) {
return pv->getKind() == PersistentExpressionState::eKindClang;
}
@@ -45,7 +40,7 @@ public:
CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) override;
lldb::ExpressionVariableSP CreatePersistentVariable(
- ExecutionContextScope *exe_scope, const ConstString &name,
+ ExecutionContextScope *exe_scope, ConstString name,
const CompilerType &compiler_type, lldb::ByteOrder byte_order,
uint32_t addr_byte_size) override;
@@ -55,9 +50,12 @@ public:
return "$";
}
- void RegisterPersistentDecl(const ConstString &name, clang::NamedDecl *decl);
+ llvm::Optional<CompilerType>
+ GetCompilerTypeFromPersistentDecl(ConstString type_name) override;
+
+ void RegisterPersistentDecl(ConstString name, clang::NamedDecl *decl);
- clang::NamedDecl *GetPersistentDecl(const ConstString &name);
+ clang::NamedDecl *GetPersistentDecl(ConstString name);
void AddHandLoadedClangModule(ClangModulesDeclVendor::ModuleID module) {
m_hand_loaded_clang_modules.push_back(module);
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index f42955df07aa..2dae5b7022f3 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -1,9 +1,8 @@
//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -22,6 +21,7 @@
#include "ClangDiagnostic.h"
#include "ClangExpressionDeclMap.h"
#include "ClangExpressionParser.h"
+#include "ClangExpressionSourceCode.h"
#include "ClangModulesDeclVendor.h"
#include "ClangPersistentVariables.h"
@@ -37,6 +37,7 @@
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
@@ -55,18 +56,20 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "llvm/ADT/ScopeExit.h"
+
using namespace lldb_private;
ClangUserExpression::ClangUserExpression(
ExecutionContextScope &exe_scope, llvm::StringRef expr,
llvm::StringRef prefix, lldb::LanguageType language,
- ResultType desired_type, const EvaluateExpressionOptions &options)
+ ResultType desired_type, const EvaluateExpressionOptions &options,
+ ValueObject *ctx_obj)
: LLVMUserExpression(exe_scope, expr, prefix, language, desired_type,
- options),
- m_type_system_helper(*m_target_wp.lock().get(),
- options.GetExecutionPolicy() ==
- eExecutionPolicyTopLevel),
- m_result_delegate(exe_scope.CalculateTarget()) {
+ options, eKindClangUserExpression),
+ m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() ==
+ eExecutionPolicyTopLevel),
+ m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) {
switch (m_language) {
case lldb::eLanguageTypeC_plus_plus:
m_allow_cxx = true;
@@ -99,7 +102,7 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
}
StackFrame *frame = exe_ctx.GetFramePtr();
- if (frame == NULL) {
+ if (frame == nullptr) {
if (log)
log->Printf(" [CUE::SC] Null stack frame");
return;
@@ -131,7 +134,27 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
return;
}
- if (clang::CXXMethodDecl *method_decl =
+ if (m_ctx_obj) {
+ switch (m_ctx_obj->GetObjectRuntimeLanguage()) {
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC89:
+ case lldb::eLanguageTypeC99:
+ case lldb::eLanguageTypeC11:
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_03:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ m_in_cplusplus_method = true;
+ break;
+ case lldb::eLanguageTypeObjC:
+ case lldb::eLanguageTypeObjC_plus_plus:
+ m_in_objectivec_method = true;
+ break;
+ default:
+ break;
+ }
+ m_needs_object_ptr = true;
+ } else if (clang::CXXMethodDecl *method_decl =
ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) {
if (m_allow_cxx && method_decl->isInstance()) {
if (m_enforce_valid_object) {
@@ -307,21 +330,6 @@ static void ApplyObjcCastHack(std::string &expr) {
#undef OBJC_CAST_HACK_FROM
}
-namespace {
-// Utility guard that calls a callback when going out of scope.
-class OnExit {
-public:
- typedef std::function<void(void)> Callback;
-
- OnExit(Callback const &callback) : m_callback(callback) {}
-
- ~OnExit() { m_callback(); }
-
-private:
- Callback m_callback;
-};
-} // namespace
-
bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx) {
if (Target *target = exe_ctx.GetTargetPtr()) {
@@ -377,7 +385,8 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target) {
}
void ClangUserExpression::UpdateLanguageForExpr(
- DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+ std::vector<std::string> modules_to_import, bool for_completion) {
m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown;
std::string prefix = m_expr_prefix;
@@ -385,8 +394,8 @@ void ClangUserExpression::UpdateLanguageForExpr(
if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {
m_transformed_text = m_expr_text;
} else {
- std::unique_ptr<ExpressionSourceCode> source_code(
- ExpressionSourceCode::CreateWrapped(prefix.c_str(),
+ std::unique_ptr<ClangExpressionSourceCode> source_code(
+ ClangExpressionSourceCode::CreateWrapped(prefix.c_str(),
m_expr_text.c_str()));
if (m_in_cplusplus_method)
@@ -397,7 +406,8 @@ void ClangUserExpression::UpdateLanguageForExpr(
m_expr_lang = lldb::eLanguageTypeC;
if (!source_code->GetText(m_transformed_text, m_expr_lang,
- m_in_static_method, exe_ctx)) {
+ m_in_static_method, exe_ctx, !m_ctx_obj,
+ for_completion, modules_to_import)) {
diagnostic_manager.PutString(eDiagnosticSeverityError,
"couldn't construct expression body");
return;
@@ -409,14 +419,73 @@ void ClangUserExpression::UpdateLanguageForExpr(
std::size_t original_end;
bool found_bounds = source_code->GetOriginalBodyBounds(
m_transformed_text, m_expr_lang, original_start, original_end);
- if (found_bounds) {
+ if (found_bounds)
m_user_expression_start_pos = original_start;
+ }
+}
+
+static bool SupportsCxxModuleImport(lldb::LanguageType language) {
+ switch (language) {
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_03:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ case lldb::eLanguageTypeObjC_plus_plus:
+ return true;
+ default:
+ return false;
+ }
+}
+
+std::vector<std::string>
+ClangUserExpression::GetModulesToImport(ExecutionContext &exe_ctx) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!SupportsCxxModuleImport(Language()))
+ return {};
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (!target || !target->GetEnableImportStdModule())
+ return {};
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (!frame)
+ return {};
+
+ Block *block = frame->GetFrameBlock();
+ if (!block)
+ return {};
+
+ SymbolContext sc;
+ block->CalculateSymbolContext(&sc);
+ if (!sc.comp_unit)
+ return {};
+
+ if (log) {
+ for (const SourceModule &m : sc.comp_unit->GetImportedModules()) {
+ LLDB_LOG(log, "Found module in compile unit: {0:$[.]} - include dir: {1}",
+ llvm::make_range(m.path.begin(), m.path.end()), m.search_path);
}
}
+
+ for (const SourceModule &m : sc.comp_unit->GetImportedModules())
+ m_include_directories.push_back(m.search_path);
+
+ // Check if we imported 'std' or any of its submodules.
+ // We currently don't support importing any other modules in the expression
+ // parser.
+ for (const SourceModule &m : sc.comp_unit->GetImportedModules())
+ if (!m.path.empty() && m.path.front() == "std")
+ return {"std"};
+
+ return {};
}
bool ClangUserExpression::PrepareForParsing(
- DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+ bool for_completion) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
InstallContext(exe_ctx);
if (!SetupPersistentState(diagnostic_manager, exe_ctx))
@@ -437,7 +506,14 @@ bool ClangUserExpression::PrepareForParsing(
SetupDeclVendor(exe_ctx, m_target);
- UpdateLanguageForExpr(diagnostic_manager, exe_ctx);
+ std::vector<std::string> used_modules = GetModulesToImport(exe_ctx);
+ m_imported_cpp_modules = !used_modules.empty();
+
+ LLDB_LOG(log, "List of imported modules in expression: {0}",
+ llvm::make_range(used_modules.begin(), used_modules.end()));
+
+ UpdateLanguageForExpr(diagnostic_manager, exe_ctx, used_modules,
+ for_completion);
return true;
}
@@ -448,7 +524,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
bool generate_debug_info) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
- if (!PrepareForParsing(diagnostic_manager, exe_ctx))
+ if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false))
return false;
if (log)
@@ -469,13 +545,13 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
// Parse the expression
//
- m_materializer_ap.reset(new Materializer());
+ m_materializer_up.reset(new Materializer());
ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);
- OnExit on_exit([this]() { ResetDeclMap(); });
+ auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });
- if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) {
+ if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"current process state is unsuitable for expression parsing");
@@ -496,7 +572,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
// succeeds or the rewrite parser we might make if it fails. But the
// parser_sp will never be empty.
- ClangExpressionParser parser(exe_scope, *this, generate_debug_info);
+ ClangExpressionParser parser(exe_scope, *this, generate_debug_info,
+ m_include_directories);
unsigned num_errors = parser.Parse(diagnostic_manager);
@@ -509,7 +586,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
size_t fixed_end;
const std::string &fixed_expression =
diagnostic_manager.GetFixedExpression();
- if (ExpressionSourceCode::GetOriginalBodyBounds(
+ if (ClangExpressionSourceCode::GetOriginalBodyBounds(
fixed_expression, m_expr_lang, fixed_start, fixed_end))
m_fixed_text =
fixed_expression.substr(fixed_start, fixed_end - fixed_start);
@@ -518,7 +595,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
return false;
}
- //////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
// Prepare the output of the parser for execution, evaluating it statically
// if possible
//
@@ -597,25 +674,23 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,
return true;
}
-//------------------------------------------------------------------
/// Converts an absolute position inside a given code string into
/// a column/line pair.
///
-/// @param[in] abs_pos
+/// \param[in] abs_pos
/// A absolute position in the code string that we want to convert
/// to a column/line pair.
///
-/// @param[in] code
+/// \param[in] code
/// A multi-line string usually representing source code.
///
-/// @param[out] line
+/// \param[out] line
/// The line in the code that contains the given absolute position.
/// The first line in the string is indexed as 1.
///
-/// @param[out] column
+/// \param[out] column
/// The column in the line that contains the absolute position.
/// The first character in a line is indexed as 0.
-//------------------------------------------------------------------
static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code,
unsigned &line, unsigned &column) {
// Reset to code position to beginning of the file.
@@ -648,7 +723,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
// correct.
DiagnosticManager diagnostic_manager;
- if (!PrepareForParsing(diagnostic_manager, exe_ctx))
+ if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ true))
return false;
if (log)
@@ -658,13 +733,13 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,
// Parse the expression
//
- m_materializer_ap.reset(new Materializer());
+ m_materializer_up.reset(new Materializer());
ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true);
- OnExit on_exit([this]() { ResetDeclMap(); });
+ auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });
- if (!DeclMap()->WillParse(exe_ctx, m_materializer_ap.get())) {
+ if (!DeclMap()->WillParse(exe_ctx, m_materializer_up.get())) {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"current process state is unsuitable for expression parsing");
@@ -734,7 +809,15 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,
Status object_ptr_error;
- object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
+ if (m_ctx_obj) {
+ AddressType address_type;
+ object_ptr = m_ctx_obj->GetAddressOf(false, &address_type);
+ if (object_ptr == LLDB_INVALID_ADDRESS ||
+ address_type != eAddressTypeLoad)
+ object_ptr_error.SetErrorString("Can't get context object's "
+ "debuggee address");
+ } else
+ object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
if (!object_ptr_error.Success()) {
exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf(
@@ -777,9 +860,11 @@ lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization(
void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
ExecutionContext &exe_ctx,
Materializer::PersistentVariableDelegate &delegate,
- bool keep_result_in_memory) {
+ bool keep_result_in_memory,
+ ValueObject *ctx_obj) {
m_expr_decl_map_up.reset(
- new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx));
+ new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx,
+ ctx_obj));
}
clang::ASTConsumer *
@@ -792,7 +877,7 @@ ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(
}
void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() {
- if (m_result_synthesizer_up.get()) {
+ if (m_result_synthesizer_up) {
m_result_synthesizer_up->CommitPersistentDecls();
}
}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
index 7e4cba661850..24c152bdb45d 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -1,9 +1,8 @@
//===-- ClangUserExpression.h -----------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -29,8 +28,7 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ClangUserExpression ClangUserExpression.h
+/// \class ClangUserExpression ClangUserExpression.h
/// "lldb/Expression/ClangUserExpression.h" Encapsulates a single expression
/// for use with Clang
///
@@ -38,9 +36,13 @@ namespace lldb_private {
/// and as a backend for the expr command. ClangUserExpression encapsulates
/// the objects needed to parse and interpret or JIT an expression. It uses
/// the Clang parser to produce LLVM IR from the expression.
-//----------------------------------------------------------------------
class ClangUserExpression : public LLVMUserExpression {
public:
+ /// LLVM-style RTTI support.
+ static bool classof(const Expression *E) {
+ return E->getKind() == eKindClangUserExpression;
+ }
+
enum { kDefaultTimeout = 500000u };
class ClangUserExpressionHelper : public ClangExpressionHelper {
@@ -50,10 +52,8 @@ public:
~ClangUserExpressionHelper() override = default;
- //------------------------------------------------------------------
/// Return the object that the parser should use when resolving external
/// values. May be NULL if everything should be self-contained.
- //------------------------------------------------------------------
ClangExpressionDeclMap *DeclMap() override {
return m_expr_decl_map_up.get();
}
@@ -62,16 +62,15 @@ public:
void ResetDeclMap(ExecutionContext &exe_ctx,
Materializer::PersistentVariableDelegate &result_delegate,
- bool keep_result_in_memory);
+ bool keep_result_in_memory,
+ ValueObject *ctx_obj);
- //------------------------------------------------------------------
/// Return the object that the parser should allow to access ASTs. May be
/// NULL if the ASTs do not need to be transformed.
///
- /// @param[in] passthrough
+ /// \param[in] passthrough
/// The ASTConsumer that the returned transformer should send
/// the ASTs to after transformation.
- //------------------------------------------------------------------
clang::ASTConsumer *
ASTTransformer(clang::ASTConsumer *passthrough) override;
@@ -88,53 +87,55 @@ public:
bool m_top_level;
};
- //------------------------------------------------------------------
/// Constructor
///
- /// @param[in] expr
+ /// \param[in] expr
/// The expression to parse.
///
- /// @param[in] expr_prefix
+ /// \param[in] expr_prefix
/// If non-NULL, a C string containing translation-unit level
/// definitions to be included when the expression is parsed.
///
- /// @param[in] language
+ /// \param[in] language
/// If not eLanguageTypeUnknown, a language to use when parsing
/// the expression. Currently restricted to those languages
/// supported by Clang.
///
- /// @param[in] desired_type
+ /// \param[in] desired_type
/// If not eResultTypeAny, the type to use for the expression
/// result.
- //------------------------------------------------------------------
+ ///
+ /// \param[in] ctx_obj
+ /// The object (if any) in which context the expression
+ /// must be evaluated. For details see the comment to
+ /// `UserExpression::Evaluate`.
ClangUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr,
llvm::StringRef prefix, lldb::LanguageType language,
ResultType desired_type,
- const EvaluateExpressionOptions &options);
+ const EvaluateExpressionOptions &options,
+ ValueObject *ctx_obj);
~ClangUserExpression() override;
- //------------------------------------------------------------------
/// Parse the expression
///
- /// @param[in] diagnostic_manager
+ /// \param[in] diagnostic_manager
/// A diagnostic manager to report parse errors and warnings to.
///
- /// @param[in] exe_ctx
+ /// \param[in] exe_ctx
/// The execution context to use when looking up entities that
/// are needed for parsing (locations of functions, types of
/// variables, persistent variables, etc.)
///
- /// @param[in] execution_policy
+ /// \param[in] execution_policy
/// Determines whether interpretation is possible or mandatory.
///
- /// @param[in] keep_result_in_memory
+ /// \param[in] keep_result_in_memory
/// True if the resulting persistent variable should reside in
/// target memory, if applicable.
///
- /// @return
+ /// \return
/// True on success (no errors); false otherwise.
- //------------------------------------------------------------------
bool Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
lldb_private::ExecutionPolicy execution_policy,
bool keep_result_in_memory, bool generate_debug_info) override;
@@ -154,17 +155,18 @@ public:
Materializer::PersistentVariableDelegate &result_delegate,
bool keep_result_in_memory) {
m_type_system_helper.ResetDeclMap(exe_ctx, result_delegate,
- keep_result_in_memory);
+ keep_result_in_memory,
+ m_ctx_obj);
}
lldb::ExpressionVariableSP
GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override;
+ bool DidImportCxxModules() const { return m_imported_cpp_modules; }
+
private:
- //------------------------------------------------------------------
/// Populate m_in_cplusplus_method and m_in_objectivec_method based on the
/// environment.
- //------------------------------------------------------------------
void ScanContext(ExecutionContext &exe_ctx,
lldb_private::Status &err) override;
@@ -173,12 +175,15 @@ private:
lldb::addr_t struct_address,
DiagnosticManager &diagnostic_manager) override;
+ std::vector<std::string> GetModulesToImport(ExecutionContext &exe_ctx);
void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager,
- ExecutionContext &exe_ctx);
+ ExecutionContext &exe_ctx,
+ std::vector<std::string> modules_to_import,
+ bool for_completion);
bool SetupPersistentState(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx);
bool PrepareForParsing(DiagnosticManager &diagnostic_manager,
- ExecutionContext &exe_ctx);
+ ExecutionContext &exe_ctx, bool for_completion);
ClangUserExpressionHelper m_type_system_helper;
@@ -199,12 +204,21 @@ private:
/// 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<ConstString> m_include_directories;
/// The absolute character position in the transformed source code where the
/// user code (as typed by the user) starts. If the variable is empty, then we
/// were not able to calculate this position.
llvm::Optional<size_t> m_user_expression_start_pos;
ResultDelegate m_result_delegate;
+
+ /// The object (if any) in which context the expression is evaluated.
+ /// See the comment to `UserExpression::Evaluate` for details.
+ ValueObject *m_ctx_obj;
+
+ /// True iff this expression explicitly imported C++ modules.
+ bool m_imported_cpp_modules = false;
};
} // namespace lldb_private
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
index fe6ca450a79d..5eec224477fc 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
+++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -1,15 +1,15 @@
//===-- ClangUtilityFunction.cpp ---------------------------------*- C++-*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 "ClangUtilityFunction.h"
#include "ClangExpressionDeclMap.h"
#include "ClangExpressionParser.h"
+#include "ClangExpressionSourceCode.h"
#include <stdio.h>
#if HAVE_SYS_TYPES_H
@@ -19,7 +19,6 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/StreamFile.h"
-#include "lldb/Expression/ExpressionSourceCode.h"
#include "lldb/Expression/IRExecutionUnit.h"
#include "lldb/Host/Host.h"
#include "lldb/Target/ExecutionContext.h"
@@ -30,33 +29,33 @@
using namespace lldb_private;
-//------------------------------------------------------------------
/// Constructor
///
-/// @param[in] text
+/// \param[in] text
/// The text of the function. Must be a full translation unit.
///
-/// @param[in] name
+/// \param[in] name
/// The name of the function, as used in the text.
-//------------------------------------------------------------------
ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
const char *text, const char *name)
- : UtilityFunction(exe_scope, text, name) {}
+ : UtilityFunction(exe_scope, text, name, eKindClangUtilityFunction) {
+ m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix);
+ if (text && text[0])
+ m_function_text.append(text);
+}
ClangUtilityFunction::~ClangUtilityFunction() {}
-//------------------------------------------------------------------
/// Install the utility function into a process
///
-/// @param[in] diagnostic_manager
+/// \param[in] diagnostic_manager
/// A diagnostic manager to report errors and warnings to.
///
-/// @param[in] exe_ctx
+/// \param[in] exe_ctx
/// The execution context to install the utility function to.
///
-/// @return
+/// \return
/// True on success (no errors); false otherwise.
-//------------------------------------------------------------------
bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
ExecutionContext &exe_ctx) {
if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
@@ -91,7 +90,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
ResetDeclMap(exe_ctx, keep_result_in_memory);
- if (!DeclMap()->WillParse(exe_ctx, NULL)) {
+ if (!DeclMap()->WillParse(exe_ctx, nullptr)) {
diagnostic_manager.PutString(
eDiagnosticSeverityError,
"current process state is unsuitable for expression parsing");
@@ -157,5 +156,6 @@ 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));
+ new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx,
+ nullptr));
}
diff --git a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
index b0650f0eda02..70ebb2f3ad8a 100644
--- a/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
+++ b/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h
@@ -1,9 +1,8 @@
//===-- ClangUtilityFunction.h ----------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -23,8 +22,7 @@
namespace lldb_private {
-//----------------------------------------------------------------------
-/// @class ClangUtilityFunction ClangUtilityFunction.h
+/// \class ClangUtilityFunction ClangUtilityFunction.h
/// "lldb/Expression/ClangUtilityFunction.h" Encapsulates a single expression
/// for use with Clang
///
@@ -34,19 +32,21 @@ namespace lldb_private {
/// functions can perform error-checking for ClangUserExpressions, or can
/// simply provide a way to push a function into the target for the debugger
/// to call later on.
-//----------------------------------------------------------------------
class ClangUtilityFunction : public UtilityFunction {
public:
+ /// LLVM-style RTTI support.
+ static bool classof(const Expression *E) {
+ return E->getKind() == eKindClangUtilityFunction;
+ }
+
class ClangUtilityFunctionHelper : public ClangExpressionHelper {
public:
ClangUtilityFunctionHelper() {}
~ClangUtilityFunctionHelper() override {}
- //------------------------------------------------------------------
/// Return the object that the parser should use when resolving external
/// values. May be NULL if everything should be self-contained.
- //------------------------------------------------------------------
ClangExpressionDeclMap *DeclMap() override {
return m_expr_decl_map_up.get();
}
@@ -55,14 +55,12 @@ public:
void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory);
- //------------------------------------------------------------------
/// Return the object that the parser should allow to access ASTs. May be
/// NULL if the ASTs do not need to be transformed.
///
- /// @param[in] passthrough
+ /// \param[in] passthrough
/// The ASTConsumer that the returned transformer should send
/// the ASTs to after transformation.
- //------------------------------------------------------------------
clang::ASTConsumer *
ASTTransformer(clang::ASTConsumer *passthrough) override {
return nullptr;
@@ -71,15 +69,13 @@ public:
private:
std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up;
};
- //------------------------------------------------------------------
/// Constructor
///
- /// @param[in] text
+ /// \param[in] text
/// The text of the function. Must be a full translation unit.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the function, as used in the text.
- //------------------------------------------------------------------
ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text,
const char *name);
diff --git a/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp
new file mode 100644
index 000000000000..f8e004fe7d4a
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp
@@ -0,0 +1,595 @@
+//===-- IRDynamicChecks.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "IRDynamicChecks.h"
+
+#include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
+
+using namespace llvm;
+using namespace lldb_private;
+
+static char ID;
+
+#define VALID_POINTER_CHECK_NAME "_$__lldb_valid_pointer_check"
+#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
+
+static const char g_valid_pointer_check_text[] =
+ "extern \"C\" void\n"
+ "_$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"
+ "{\n"
+ " unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n"
+ "}";
+
+ClangDynamicCheckerFunctions::ClangDynamicCheckerFunctions()
+ : DynamicCheckerFunctions(DCF_Clang) {}
+
+ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default;
+
+bool ClangDynamicCheckerFunctions::Install(
+ DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+ Status error;
+ m_valid_pointer_check.reset(
+ exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage(
+ g_valid_pointer_check_text, lldb::eLanguageTypeC,
+ VALID_POINTER_CHECK_NAME, error));
+ if (error.Fail())
+ return false;
+
+ if (!m_valid_pointer_check->Install(diagnostic_manager, exe_ctx))
+ return false;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process) {
+ ObjCLanguageRuntime *objc_language_runtime =
+ ObjCLanguageRuntime::Get(*process);
+
+ if (objc_language_runtime) {
+ m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker(
+ VALID_OBJC_OBJECT_CHECK_NAME));
+
+ if (!m_objc_object_check->Install(diagnostic_manager, exe_ctx))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ClangDynamicCheckerFunctions::DoCheckersExplainStop(lldb::addr_t addr,
+ Stream &message) {
+ // FIXME: We have to get the checkers to know why they scotched the call in
+ // more detail,
+ // so we can print a better message here.
+ if (m_valid_pointer_check && m_valid_pointer_check->ContainsAddress(addr)) {
+ message.Printf("Attempted to dereference an invalid pointer.");
+ return true;
+ } else if (m_objc_object_check &&
+ m_objc_object_check->ContainsAddress(addr)) {
+ message.Printf("Attempted to dereference an invalid ObjC Object or send it "
+ "an unrecognized selector");
+ return true;
+ }
+ return false;
+}
+
+static std::string PrintValue(llvm::Value *V, bool truncate = false) {
+ std::string s;
+ raw_string_ostream rso(s);
+ V->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+/// \class Instrumenter IRDynamicChecks.cpp
+/// Finds and instruments individual LLVM IR instructions
+///
+/// When instrumenting LLVM IR, it is frequently desirable to first search for
+/// instructions, and then later modify them. This way iterators remain
+/// intact, and multiple passes can look at the same code base without
+/// treading on each other's toes.
+///
+/// The Instrumenter class implements this functionality. A client first
+/// calls Inspect on a function, which populates a list of instructions to be
+/// instrumented. Then, later, when all passes' Inspect functions have been
+/// called, the client calls Instrument, which adds the desired
+/// instrumentation.
+///
+/// A subclass of Instrumenter must override InstrumentInstruction, which
+/// is responsible for adding whatever instrumentation is necessary.
+///
+/// A subclass of Instrumenter may override:
+///
+/// - InspectInstruction [default: does nothing]
+///
+/// - InspectBasicBlock [default: iterates through the instructions in a
+/// basic block calling InspectInstruction]
+///
+/// - InspectFunction [default: iterates through the basic blocks in a
+/// function calling InspectBasicBlock]
+class Instrumenter {
+public:
+ /// Constructor
+ ///
+ /// \param[in] module
+ /// The module being instrumented.
+ Instrumenter(llvm::Module &module,
+ std::shared_ptr<UtilityFunction> checker_function)
+ : m_module(module), m_checker_function(checker_function),
+ m_i8ptr_ty(nullptr), m_intptr_ty(nullptr) {}
+
+ virtual ~Instrumenter() = default;
+
+ /// Inspect a function to find instructions to instrument
+ ///
+ /// \param[in] function
+ /// The function to inspect.
+ ///
+ /// \return
+ /// True on success; false on error.
+ bool Inspect(llvm::Function &function) { return InspectFunction(function); }
+
+ /// Instrument all the instructions found by Inspect()
+ ///
+ /// \return
+ /// True on success; false on error.
+ bool Instrument() {
+ for (InstIterator ii = m_to_instrument.begin(),
+ last_ii = m_to_instrument.end();
+ ii != last_ii; ++ii) {
+ if (!InstrumentInstruction(*ii))
+ return false;
+ }
+
+ return true;
+ }
+
+protected:
+ /// Add instrumentation to a single instruction
+ ///
+ /// \param[in] inst
+ /// The instruction to be instrumented.
+ ///
+ /// \return
+ /// True on success; false otherwise.
+ virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
+
+ /// Register a single instruction to be instrumented
+ ///
+ /// \param[in] inst
+ /// The instruction to be instrumented.
+ void RegisterInstruction(llvm::Instruction &i) {
+ m_to_instrument.push_back(&i);
+ }
+
+ /// Determine whether a single instruction is interesting to instrument,
+ /// and, if so, call RegisterInstruction
+ ///
+ /// \param[in] i
+ /// The instruction to be inspected.
+ ///
+ /// \return
+ /// False if there was an error scanning; true otherwise.
+ virtual bool InspectInstruction(llvm::Instruction &i) { return true; }
+
+ /// Scan a basic block to see if any instructions are interesting
+ ///
+ /// \param[in] bb
+ /// The basic block to be inspected.
+ ///
+ /// \return
+ /// False if there was an error scanning; true otherwise.
+ virtual bool InspectBasicBlock(llvm::BasicBlock &bb) {
+ for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();
+ ii != last_ii; ++ii) {
+ if (!InspectInstruction(*ii))
+ return false;
+ }
+
+ return true;
+ }
+
+ /// Scan a function to see if any instructions are interesting
+ ///
+ /// \param[in] f
+ /// The function to be inspected.
+ ///
+ /// \return
+ /// False if there was an error scanning; true otherwise.
+ virtual bool InspectFunction(llvm::Function &f) {
+ for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
+ bbi != last_bbi; ++bbi) {
+ if (!InspectBasicBlock(*bbi))
+ return false;
+ }
+
+ return true;
+ }
+
+ /// Build a function pointer for a function with signature void
+ /// (*)(uint8_t*) with a given address
+ ///
+ /// \param[in] start_address
+ /// The address of the function.
+ ///
+ /// \return
+ /// The function pointer, for use in a CallInst.
+ llvm::FunctionCallee BuildPointerValidatorFunc(lldb::addr_t start_address) {
+ llvm::Type *param_array[1];
+
+ param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
+
+ ArrayRef<llvm::Type *> params(param_array, 1);
+
+ FunctionType *fun_ty = FunctionType::get(
+ llvm::Type::getVoidTy(m_module.getContext()), params, true);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
+ Constant *fun_addr_int =
+ ConstantInt::get(GetIntptrTy(), start_address, false);
+ return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
+ }
+
+ /// Build a function pointer for a function with signature void
+ /// (*)(uint8_t*, uint8_t*) with a given address
+ ///
+ /// \param[in] start_address
+ /// The address of the function.
+ ///
+ /// \return
+ /// The function pointer, for use in a CallInst.
+ llvm::FunctionCallee BuildObjectCheckerFunc(lldb::addr_t start_address) {
+ llvm::Type *param_array[2];
+
+ param_array[0] = const_cast<llvm::PointerType *>(GetI8PtrTy());
+ param_array[1] = const_cast<llvm::PointerType *>(GetI8PtrTy());
+
+ ArrayRef<llvm::Type *> params(param_array, 2);
+
+ FunctionType *fun_ty = FunctionType::get(
+ llvm::Type::getVoidTy(m_module.getContext()), params, true);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
+ Constant *fun_addr_int =
+ ConstantInt::get(GetIntptrTy(), start_address, false);
+ return {fun_ty, ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty)};
+ }
+
+ PointerType *GetI8PtrTy() {
+ if (!m_i8ptr_ty)
+ m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext());
+
+ return m_i8ptr_ty;
+ }
+
+ IntegerType *GetIntptrTy() {
+ if (!m_intptr_ty) {
+ llvm::DataLayout data_layout(&m_module);
+
+ m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
+ data_layout.getPointerSizeInBits());
+ }
+
+ return m_intptr_ty;
+ }
+
+ typedef std::vector<llvm::Instruction *> InstVector;
+ typedef InstVector::iterator InstIterator;
+
+ InstVector m_to_instrument; ///< List of instructions the inspector found
+ llvm::Module &m_module; ///< The module which is being instrumented
+ std::shared_ptr<UtilityFunction>
+ m_checker_function; ///< The dynamic checker function for the process
+
+private:
+ PointerType *m_i8ptr_ty;
+ IntegerType *m_intptr_ty;
+};
+
+class ValidPointerChecker : public Instrumenter {
+public:
+ ValidPointerChecker(llvm::Module &module,
+ std::shared_ptr<UtilityFunction> checker_function)
+ : Instrumenter(module, checker_function),
+ m_valid_pointer_check_func(nullptr) {}
+
+ ~ValidPointerChecker() override = default;
+
+protected:
+ bool InstrumentInstruction(llvm::Instruction *inst) override {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("Instrumenting load/store instruction: %s\n",
+ PrintValue(inst).c_str());
+
+ if (!m_valid_pointer_check_func)
+ m_valid_pointer_check_func =
+ BuildPointerValidatorFunc(m_checker_function->StartAddress());
+
+ llvm::Value *dereferenced_ptr = nullptr;
+
+ if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst>(inst))
+ dereferenced_ptr = li->getPointerOperand();
+ else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst>(inst))
+ dereferenced_ptr = si->getPointerOperand();
+ else
+ return false;
+
+ // Insert an instruction to cast the loaded value to int8_t*
+
+ BitCastInst *bit_cast =
+ new BitCastInst(dereferenced_ptr, GetI8PtrTy(), "", inst);
+
+ // Insert an instruction to call the helper with the result
+
+ llvm::Value *arg_array[1];
+
+ arg_array[0] = bit_cast;
+
+ llvm::ArrayRef<llvm::Value *> args(arg_array, 1);
+
+ CallInst::Create(m_valid_pointer_check_func, args, "", inst);
+
+ return true;
+ }
+
+ bool InspectInstruction(llvm::Instruction &i) override {
+ if (dyn_cast<llvm::LoadInst>(&i) || dyn_cast<llvm::StoreInst>(&i))
+ RegisterInstruction(i);
+
+ return true;
+ }
+
+private:
+ llvm::FunctionCallee m_valid_pointer_check_func;
+};
+
+class ObjcObjectChecker : public Instrumenter {
+public:
+ ObjcObjectChecker(llvm::Module &module,
+ std::shared_ptr<UtilityFunction> checker_function)
+ : Instrumenter(module, checker_function),
+ m_objc_object_check_func(nullptr) {}
+
+ ~ObjcObjectChecker() override = default;
+
+ enum msgSend_type {
+ eMsgSend = 0,
+ eMsgSendSuper,
+ eMsgSendSuper_stret,
+ eMsgSend_fpret,
+ eMsgSend_stret
+ };
+
+ std::map<llvm::Instruction *, msgSend_type> msgSend_types;
+
+protected:
+ bool InstrumentInstruction(llvm::Instruction *inst) override {
+ CallInst *call_inst = dyn_cast<CallInst>(inst);
+
+ if (!call_inst)
+ return false; // call_inst really shouldn't be nullptr, because otherwise
+ // InspectInstruction wouldn't have registered it
+
+ if (!m_objc_object_check_func)
+ m_objc_object_check_func =
+ BuildObjectCheckerFunc(m_checker_function->StartAddress());
+
+ // id objc_msgSend(id theReceiver, SEL theSelector, ...)
+
+ llvm::Value *target_object;
+ llvm::Value *selector;
+
+ switch (msgSend_types[inst]) {
+ case eMsgSend:
+ case eMsgSend_fpret:
+ // On arm64, clang uses objc_msgSend for scalar and struct return
+ // calls. The call instruction will record which was used.
+ if (call_inst->hasStructRetAttr()) {
+ target_object = call_inst->getArgOperand(1);
+ selector = call_inst->getArgOperand(2);
+ } else {
+ target_object = call_inst->getArgOperand(0);
+ selector = call_inst->getArgOperand(1);
+ }
+ break;
+ case eMsgSend_stret:
+ target_object = call_inst->getArgOperand(1);
+ selector = call_inst->getArgOperand(2);
+ break;
+ case eMsgSendSuper:
+ case eMsgSendSuper_stret:
+ return true;
+ }
+
+ // These objects should always be valid according to Sean Calannan
+ assert(target_object);
+ assert(selector);
+
+ // Insert an instruction to cast the receiver id to int8_t*
+
+ BitCastInst *bit_cast =
+ new BitCastInst(target_object, GetI8PtrTy(), "", inst);
+
+ // Insert an instruction to call the helper with the result
+
+ llvm::Value *arg_array[2];
+
+ arg_array[0] = bit_cast;
+ arg_array[1] = selector;
+
+ ArrayRef<llvm::Value *> args(arg_array, 2);
+
+ CallInst::Create(m_objc_object_check_func, args, "", inst);
+
+ return true;
+ }
+
+ static llvm::Function *GetFunction(llvm::Value *value) {
+ if (llvm::Function *function = llvm::dyn_cast<llvm::Function>(value)) {
+ return function;
+ }
+
+ if (llvm::ConstantExpr *const_expr =
+ llvm::dyn_cast<llvm::ConstantExpr>(value)) {
+ switch (const_expr->getOpcode()) {
+ default:
+ return nullptr;
+ case llvm::Instruction::BitCast:
+ return GetFunction(const_expr->getOperand(0));
+ }
+ }
+
+ return nullptr;
+ }
+
+ static llvm::Function *GetCalledFunction(llvm::CallInst *inst) {
+ return GetFunction(inst->getCalledValue());
+ }
+
+ bool InspectInstruction(llvm::Instruction &i) override {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ CallInst *call_inst = dyn_cast<CallInst>(&i);
+
+ if (call_inst) {
+ const llvm::Function *called_function = GetCalledFunction(call_inst);
+
+ if (!called_function)
+ return true;
+
+ std::string name_str = called_function->getName().str();
+ const char *name_cstr = name_str.c_str();
+
+ if (log)
+ log->Printf("Found call to %s: %s\n", name_cstr,
+ PrintValue(call_inst).c_str());
+
+ if (name_str.find("objc_msgSend") == std::string::npos)
+ return true;
+
+ if (!strcmp(name_cstr, "objc_msgSend")) {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSend_stret")) {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend_stret;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSend_fpret")) {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend_fpret;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSendSuper")) {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSendSuper;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSendSuper_stret")) {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSendSuper_stret;
+ return true;
+ }
+
+ if (log)
+ log->Printf(
+ "Function name '%s' contains 'objc_msgSend' but is not handled",
+ name_str.c_str());
+
+ return true;
+ }
+
+ return true;
+ }
+
+private:
+ llvm::FunctionCallee m_objc_object_check_func;
+};
+
+IRDynamicChecks::IRDynamicChecks(
+ ClangDynamicCheckerFunctions &checker_functions, const char *func_name)
+ : ModulePass(ID), m_func_name(func_name),
+ m_checker_functions(checker_functions) {}
+
+IRDynamicChecks::~IRDynamicChecks() = default;
+
+bool IRDynamicChecks::runOnModule(llvm::Module &M) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+ llvm::Function *function = M.getFunction(StringRef(m_func_name));
+
+ if (!function) {
+ if (log)
+ log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
+
+ return false;
+ }
+
+ if (m_checker_functions.m_valid_pointer_check) {
+ ValidPointerChecker vpc(M, m_checker_functions.m_valid_pointer_check);
+
+ if (!vpc.Inspect(*function))
+ return false;
+
+ if (!vpc.Instrument())
+ return false;
+ }
+
+ if (m_checker_functions.m_objc_object_check) {
+ ObjcObjectChecker ooc(M, m_checker_functions.m_objc_object_check);
+
+ if (!ooc.Inspect(*function))
+ return false;
+
+ if (!ooc.Instrument())
+ return false;
+ }
+
+ if (log && log->GetVerbose()) {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ M.print(oss, nullptr);
+
+ oss.flush();
+
+ log->Printf("Module after dynamic checks: \n%s", s.c_str());
+ }
+
+ return true;
+}
+
+void IRDynamicChecks::assignPassManager(PMStack &PMS, PassManagerType T) {}
+
+PassManagerType IRDynamicChecks::getPotentialPassManagerType() const {
+ return PMT_ModulePassManager;
+}
diff --git a/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h
new file mode 100644
index 000000000000..60c0691b21c1
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.h
@@ -0,0 +1,131 @@
+//===-- IRDynamicChecks.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 liblldb_IRDynamicChecks_h_
+#define liblldb_IRDynamicChecks_h_
+
+#include "lldb/Expression/DynamicCheckerFunctions.h"
+#include "lldb/lldb-types.h"
+#include "llvm/Pass.h"
+
+namespace llvm {
+class BasicBlock;
+class Module;
+}
+
+namespace lldb_private {
+
+class ExecutionContext;
+class Stream;
+
+class ClangDynamicCheckerFunctions
+ : public lldb_private::DynamicCheckerFunctions {
+public:
+ /// Constructor
+ ClangDynamicCheckerFunctions();
+
+ /// Destructor
+ virtual ~ClangDynamicCheckerFunctions();
+
+ static bool classof(const DynamicCheckerFunctions *checker_funcs) {
+ return checker_funcs->GetKind() == DCF_Clang;
+ }
+
+ /// Install the utility functions into a process. This binds the instance
+ /// of DynamicCheckerFunctions to that process.
+ ///
+ /// \param[in] diagnostic_manager
+ /// A diagnostic manager to report errors to.
+ ///
+ /// \param[in] exe_ctx
+ /// The execution context to install the functions into.
+ ///
+ /// \return
+ /// True on success; false on failure, or if the functions have
+ /// already been installed.
+ bool Install(DiagnosticManager &diagnostic_manager,
+ ExecutionContext &exe_ctx) override;
+
+ bool DoCheckersExplainStop(lldb::addr_t addr, Stream &message) override;
+
+ std::shared_ptr<UtilityFunction> m_valid_pointer_check;
+ std::shared_ptr<UtilityFunction> m_objc_object_check;
+};
+
+/// \class IRDynamicChecks IRDynamicChecks.h
+/// "lldb/Expression/IRDynamicChecks.h" Adds dynamic checks to a user-entered
+/// expression to reduce its likelihood of crashing
+///
+/// When an IR function is executed in the target process, it may cause
+/// crashes or hangs by dereferencing NULL pointers, trying to call
+/// Objective-C methods on objects that do not respond to them, and so forth.
+///
+/// IRDynamicChecks adds calls to the functions in DynamicCheckerFunctions to
+/// appropriate locations in an expression's IR.
+class IRDynamicChecks : public llvm::ModulePass {
+public:
+ /// Constructor
+ ///
+ /// \param[in] checker_functions
+ /// The checker functions for the target process.
+ ///
+ /// \param[in] func_name
+ /// The name of the function to prepare for execution in the target.
+ ///
+ /// \param[in] decl_map
+ /// The mapping used to look up entities in the target process. In
+ /// this case, used to find objc_msgSend
+ IRDynamicChecks(ClangDynamicCheckerFunctions &checker_functions,
+ const char *func_name = "$__lldb_expr");
+
+ /// Destructor
+ ~IRDynamicChecks() override;
+
+ /// Run this IR transformer on a single module
+ ///
+ /// \param[in] M
+ /// The module to run on. This module is searched for the function
+ /// $__lldb_expr, and that function is passed to the passes one by
+ /// one.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool runOnModule(llvm::Module &M) override;
+
+ /// Interface stub
+ void assignPassManager(
+ llvm::PMStack &PMS,
+ llvm::PassManagerType T = llvm::PMT_ModulePassManager) override;
+
+ /// Returns PMT_ModulePassManager
+ llvm::PassManagerType getPotentialPassManagerType() const override;
+
+private:
+ /// A basic block-level pass to find all pointer dereferences and
+ /// validate them before use.
+
+ /// The top-level pass implementation
+ ///
+ /// \param[in] M
+ /// The module currently being processed.
+ ///
+ /// \param[in] BB
+ /// The basic block currently being processed.
+ ///
+ /// \return
+ /// True on success; false otherwise
+ bool FindDataLoads(llvm::Module &M, llvm::BasicBlock &BB);
+
+ std::string m_func_name; ///< The name of the function to add checks to
+ ClangDynamicCheckerFunctions
+ &m_checker_functions; ///< The checker functions for the process
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_IRDynamicChecks_h_
diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
index 3a7cd58b70ab..07acb2e1030f 100644
--- a/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
+++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp
@@ -1,9 +1,8 @@
//===-- IRForTarget.cpp -----------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -61,7 +60,7 @@ IRForTarget::FunctionValueCache::GetValue(llvm::Function *function) {
static llvm::Value *FindEntryInstruction(llvm::Function *function) {
if (function->empty())
- return NULL;
+ return nullptr;
return function->getEntryBlock().getFirstNonPHIOrDbg();
}
@@ -72,11 +71,12 @@ IRForTarget::IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map,
lldb_private::Stream &error_stream,
const char *func_name)
: ModulePass(ID), m_resolve_vars(resolve_vars), m_func_name(func_name),
- m_module(NULL), m_decl_map(decl_map), m_CFStringCreateWithBytes(NULL),
- m_sel_registerName(NULL), m_objc_getClass(NULL), m_intptr_ty(NULL),
- m_error_stream(error_stream),
- m_execution_unit(execution_unit), m_result_store(NULL),
- m_result_is_pointer(false), m_reloc_placeholder(NULL),
+ m_module(nullptr), m_decl_map(decl_map),
+ m_CFStringCreateWithBytes(nullptr), m_sel_registerName(nullptr),
+ m_objc_getClass(nullptr), m_intptr_ty(nullptr),
+ m_error_stream(error_stream), m_execution_unit(execution_unit),
+ m_result_store(nullptr), m_result_is_pointer(false),
+ m_reloc_placeholder(nullptr),
m_entry_instruction_finder(FindEntryInstruction) {}
/* Handy utility functions used at several places in the code */
@@ -117,7 +117,7 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val,
module->getNamedMetadata("clang.global.decl.ptrs");
if (!named_metadata)
- return NULL;
+ return nullptr;
unsigned num_nodes = named_metadata->getNumOperands();
unsigned node_index;
@@ -126,7 +126,7 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val,
llvm::MDNode *metadata_node =
dyn_cast<llvm::MDNode>(named_metadata->getOperand(node_index));
if (!metadata_node)
- return NULL;
+ return nullptr;
if (metadata_node->getNumOperands() != 2)
continue;
@@ -139,14 +139,14 @@ clang::NamedDecl *IRForTarget::DeclForGlobal(const GlobalValue *global_val,
mdconst::dyn_extract<ConstantInt>(metadata_node->getOperand(1));
if (!constant_int)
- return NULL;
+ return nullptr;
uintptr_t ptr = constant_int->getZExtValue();
return reinterpret_cast<clang::NamedDecl *>(ptr);
}
- return NULL;
+ return nullptr;
}
clang::NamedDecl *IRForTarget::DeclForGlobal(GlobalValue *global_val) {
@@ -165,7 +165,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) {
ValueSymbolTable &value_symbol_table = m_module->getValueSymbolTable();
std::string result_name_str;
- const char *result_name = NULL;
+ const char *result_name = nullptr;
for (ValueSymbolTable::iterator vi = value_symbol_table.begin(),
ve = value_symbol_table.end();
@@ -343,8 +343,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) {
GlobalVariable *new_result_global = new GlobalVariable(
(*m_module), result_global->getType()->getElementType(),
- false, /* not constant */
- GlobalValue::ExternalLinkage, NULL, /* no initializer */
+ false, /* not constant */
+ GlobalValue::ExternalLinkage, nullptr, /* no initializer */
m_result_name.GetCString());
// It's too late in compilation to create a new VarDecl for this, but we
@@ -433,9 +433,11 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str,
static lldb_private::ConstString g_CFStringCreateWithBytes_str(
"CFStringCreateWithBytes");
+ bool missing_weak = false;
CFStringCreateWithBytes_addr =
- m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str);
- if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS) {
+ m_execution_unit.FindSymbol(g_CFStringCreateWithBytes_str,
+ missing_weak);
+ if (CFStringCreateWithBytes_addr == LLDB_INVALID_ADDRESS || missing_weak) {
if (log)
log->PutCString("Couldn't find CFStringCreateWithBytes in the target");
@@ -478,18 +480,18 @@ bool IRForTarget::RewriteObjCConstString(llvm::GlobalVariable *ns_str,
ArrayRef<Type *> CFSCWB_arg_types(arg_type_array, 5);
- llvm::Type *CFSCWB_ty =
+ llvm::FunctionType *CFSCWB_ty =
FunctionType::get(ns_str_ty, CFSCWB_arg_types, false);
// Build the constant containing the pointer to the function
PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty);
Constant *CFSCWB_addr_int =
ConstantInt::get(m_intptr_ty, CFStringCreateWithBytes_addr, false);
- m_CFStringCreateWithBytes =
- ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty);
+ m_CFStringCreateWithBytes = {
+ CFSCWB_ty, ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty)};
}
- ConstantDataSequential *string_array = NULL;
+ ConstantDataSequential *string_array = nullptr;
if (cstr)
string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer());
@@ -734,7 +736,7 @@ bool IRForTarget::RewriteObjCConstStrings() {
}
if (!cstr_array)
- cstr_global = NULL;
+ cstr_global = nullptr;
if (!RewriteObjCConstString(nsstring_global, cstr_global)) {
if (log)
@@ -857,9 +859,11 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) {
if (!m_sel_registerName) {
lldb::addr_t sel_registerName_addr;
+ bool missing_weak = false;
static lldb_private::ConstString g_sel_registerName_str("sel_registerName");
- sel_registerName_addr = m_execution_unit.FindSymbol(g_sel_registerName_str);
- if (sel_registerName_addr == LLDB_INVALID_ADDRESS)
+ sel_registerName_addr = m_execution_unit.FindSymbol(g_sel_registerName_str,
+ missing_weak);
+ if (sel_registerName_addr == LLDB_INVALID_ADDRESS || missing_weak)
return false;
if (log)
@@ -881,14 +885,15 @@ bool IRForTarget::RewriteObjCSelector(Instruction *selector_load) {
ArrayRef<Type *> srN_arg_types(type_array, 1);
- llvm::Type *srN_type =
+ llvm::FunctionType *srN_type =
FunctionType::get(sel_ptr_type, srN_arg_types, false);
// Build the constant containing the pointer to the function
PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
Constant *srN_addr_int =
ConstantInt::get(m_intptr_ty, sel_registerName_addr, false);
- m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty);
+ m_sel_registerName = {srN_type,
+ ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty)};
}
Value *argument_array[1];
@@ -1026,9 +1031,11 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) {
if (!m_objc_getClass) {
lldb::addr_t objc_getClass_addr;
+ bool missing_weak = false;
static lldb_private::ConstString g_objc_getClass_str("objc_getClass");
- objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str);
- if (objc_getClass_addr == LLDB_INVALID_ADDRESS)
+ objc_getClass_addr = m_execution_unit.FindSymbol(g_objc_getClass_str,
+ missing_weak);
+ if (objc_getClass_addr == LLDB_INVALID_ADDRESS || missing_weak)
return false;
if (log)
@@ -1043,14 +1050,15 @@ bool IRForTarget::RewriteObjCClassReference(Instruction *class_load) {
ArrayRef<Type *> ogC_arg_types(type_array, 1);
- llvm::Type *ogC_type =
+ llvm::FunctionType *ogC_type =
FunctionType::get(class_type, ogC_arg_types, false);
// Build the constant containing the pointer to the function
PointerType *ogC_ptr_ty = PointerType::getUnqual(ogC_type);
Constant *ogC_addr_int =
ConstantInt::get(m_intptr_ty, objc_getClass_addr, false);
- m_objc_getClass = ConstantExpr::getIntToPtr(ogC_addr_int, ogC_ptr_ty);
+ m_objc_getClass = {ogC_type,
+ ConstantExpr::getIntToPtr(ogC_addr_int, ogC_ptr_ty)};
}
Value *argument_array[1];
@@ -1148,8 +1156,8 @@ bool IRForTarget::RewritePersistentAlloc(llvm::Instruction *persistent_alloc) {
return false;
GlobalVariable *persistent_global = new GlobalVariable(
- (*m_module), alloc->getType(), false, /* not constant */
- GlobalValue::ExternalLinkage, NULL, /* no initializer */
+ (*m_module), alloc->getType(), false, /* not constant */
+ GlobalValue::ExternalLinkage, nullptr, /* no initializer */
alloc->getName().str());
// What we're going to do here is make believe this was a regular old
@@ -1345,13 +1353,13 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) {
std::string name(named_decl->getName().str());
clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl);
- if (value_decl == NULL)
+ if (value_decl == nullptr)
return false;
lldb_private::CompilerType compiler_type(&value_decl->getASTContext(),
value_decl->getType());
- const Type *value_type = NULL;
+ const Type *value_type = nullptr;
if (name[0] == '$') {
// The $__lldb_expr_result name indicates the return value has allocated
@@ -1629,12 +1637,12 @@ bool IRForTarget::ResolveExternals(Function &llvm_function) {
}
static bool isGuardVariableRef(Value *V) {
- Constant *Old = NULL;
+ Constant *Old = nullptr;
if (!(Old = dyn_cast<Constant>(V)))
return false;
- ConstantExpr *CE = NULL;
+ ConstantExpr *CE = nullptr;
if ((CE = dyn_cast<ConstantExpr>(V))) {
if (CE->getOpcode() != Instruction::BitCast)
@@ -1929,8 +1937,8 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) {
}
for (element_index = 0; element_index < num_elements; ++element_index) {
- const clang::NamedDecl *decl = NULL;
- Value *value = NULL;
+ const clang::NamedDecl *decl = nullptr;
+ Value *value = nullptr;
lldb::offset_t offset;
lldb_private::ConstString name;
@@ -2050,7 +2058,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) {
std::string s;
raw_string_ostream oss(s);
- m_module->print(oss, NULL);
+ m_module->print(oss, nullptr);
oss.flush();
@@ -2087,7 +2095,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) {
m_reloc_placeholder = new llvm::GlobalVariable(
(*m_module), int8_ty, false /* IsConstant */,
GlobalVariable::InternalLinkage, Constant::getNullValue(int8_ty),
- "reloc_placeholder", NULL /* InsertBefore */,
+ "reloc_placeholder", nullptr /* InsertBefore */,
GlobalVariable::NotThreadLocal /* ThreadLocal */, 0 /* AddressSpace */);
////////////////////////////////////////////////////////////
@@ -2109,7 +2117,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) {
std::string s;
raw_string_ostream oss(s);
- m_module->print(oss, NULL);
+ m_module->print(oss, nullptr);
oss.flush();
@@ -2244,7 +2252,7 @@ bool IRForTarget::runOnModule(Module &llvm_module) {
std::string s;
raw_string_ostream oss(s);
- m_module->print(oss, NULL);
+ m_module->print(oss, nullptr);
oss.flush();
diff --git a/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/source/Plugins/ExpressionParser/Clang/IRForTarget.h
index c6c44b46023c..f87fd8ac32cb 100644
--- a/source/Plugins/ExpressionParser/Clang/IRForTarget.h
+++ b/source/Plugins/ExpressionParser/Clang/IRForTarget.h
@@ -1,10 +1,9 @@
//===-- IRForTarget.h ---------------------------------------------*- C++
//-*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -17,6 +16,7 @@
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/lldb-public.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/Pass.h"
#include <functional>
@@ -31,11 +31,9 @@ class Function;
class GlobalValue;
class GlobalVariable;
class Instruction;
-class IntegerType;
class Module;
class StoreInst;
class DataLayout;
-class Type;
class Value;
}
@@ -45,8 +43,7 @@ class IRExecutionUnit;
class IRMemoryMap;
}
-//----------------------------------------------------------------------
-/// @class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h"
+/// \class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h"
/// Transforms the IR for a function to run in the target
///
/// Once an expression has been parsed and converted to IR, it can run in two
@@ -57,168 +54,143 @@ class IRMemoryMap;
/// transformations to the IR which make it relocatable. These
/// transformations are discussed in more detail next to their relevant
/// functions.
-//----------------------------------------------------------------------
class IRForTarget : public llvm::ModulePass {
public:
enum class LookupResult { Success, Fail, Ignore };
- //------------------------------------------------------------------
/// Constructor
///
- /// @param[in] decl_map
+ /// \param[in] decl_map
/// The list of externally-referenced variables for the expression,
/// for use in looking up globals and allocating the argument
/// struct. See the documentation for ClangExpressionDeclMap.
///
- /// @param[in] resolve_vars
+ /// \param[in] resolve_vars
/// True if the external variable references (including persistent
/// variables) should be resolved. If not, only external functions
/// are resolved.
///
- /// @param[in] execution_policy
+ /// \param[in] execution_policy
/// Determines whether an IR interpreter can be used to statically
/// evaluate the expression.
///
- /// @param[in] const_result
+ /// \param[in] const_result
/// This variable is populated with the statically-computed result
/// of the function, if it has no side-effects and the result can
/// be computed statically.
///
- /// @param[in] execution_unit
+ /// \param[in] execution_unit
/// The holder for raw data associated with the expression.
///
- /// @param[in] error_stream
+ /// \param[in] error_stream
/// If non-NULL, a stream on which errors can be printed.
///
- /// @param[in] func_name
+ /// \param[in] func_name
/// The name of the function to prepare for execution in the target.
- //------------------------------------------------------------------
IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, bool resolve_vars,
lldb_private::IRExecutionUnit &execution_unit,
lldb_private::Stream &error_stream,
const char *func_name = "$__lldb_expr");
- //------------------------------------------------------------------
/// Destructor
- //------------------------------------------------------------------
~IRForTarget() override;
- //------------------------------------------------------------------
/// Run this IR transformer on a single module
///
/// Implementation of the llvm::ModulePass::runOnModule() function.
///
- /// @param[in] llvm_module
+ /// \param[in] llvm_module
/// The module to run on. This module is searched for the function
/// $__lldb_expr, and that function is passed to the passes one by
/// one.
///
- /// @param[in] interpreter_error
+ /// \param[in] interpreter_error
/// An error. If the expression fails to be interpreted, this error
/// is set to a reason why.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool runOnModule(llvm::Module &llvm_module) override;
- //------------------------------------------------------------------
/// Interface stub
///
/// Implementation of the llvm::ModulePass::assignPassManager() function.
- //------------------------------------------------------------------
void assignPassManager(llvm::PMStack &pass_mgr_stack,
llvm::PassManagerType pass_mgr_type =
llvm::PMT_ModulePassManager) override;
- //------------------------------------------------------------------
/// Returns PMT_ModulePassManager
///
/// Implementation of the llvm::ModulePass::getPotentialPassManagerType()
/// function.
- //------------------------------------------------------------------
llvm::PassManagerType getPotentialPassManagerType() const override;
private:
- //------------------------------------------------------------------
/// Ensures that the current function's linkage is set to external.
/// Otherwise the JIT may not return an address for it.
///
- /// @param[in] llvm_function
+ /// \param[in] llvm_function
/// The function whose linkage is to be fixed.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
bool FixFunctionLinkage(llvm::Function &llvm_function);
- //------------------------------------------------------------------
/// A module-level pass to replace all function pointers with their
/// integer equivalents.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] llvm_module
+ /// \param[in] llvm_module
/// The module currently being processed.
///
- /// @param[in] llvm_function
+ /// \param[in] llvm_function
/// The function currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise.
- //------------------------------------------------------------------
bool HasSideEffects(llvm::Function &llvm_function);
- //------------------------------------------------------------------
/// A function-level pass to check whether the function has side
/// effects.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Get the address of a function, and a location to put the complete Value
/// of the function if one is available.
///
- /// @param[in] function
+ /// \param[in] function
/// The function to find the location of.
///
- /// @param[out] ptr
+ /// \param[out] ptr
/// The location of the function in the target.
///
- /// @param[out] name
+ /// \param[out] name
/// The resolved name of the function (matters for intrinsics).
///
- /// @param[out] value_ptr
+ /// \param[out] value_ptr
/// A variable to put the function's completed Value* in, or NULL
/// if the Value* shouldn't be stored anywhere.
///
- /// @return
+ /// \return
/// The pointer.
- //------------------------------------------------------------------
LookupResult GetFunctionAddress(llvm::Function *function, uint64_t &ptr,
lldb_private::ConstString &name,
llvm::Constant **&value_ptr);
- //------------------------------------------------------------------
/// A function-level pass to take the generated global value
/// $__lldb_expr_result and make it into a persistent variable. Also see
/// ASTResultSynthesizer.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Find the NamedDecl corresponding to a Value. This interface is exposed
/// for the IR interpreter.
///
- /// @param[in] module
+ /// \param[in] module
/// The module containing metadata to search
///
- /// @param[in] global
+ /// \param[in] global
/// The global entity to search for
///
- /// @return
+ /// \return
/// The corresponding variable declaration
- //------------------------------------------------------------------
public:
static clang::NamedDecl *DeclForGlobal(const llvm::GlobalValue *global_val,
llvm::Module *module);
@@ -226,75 +198,62 @@ public:
private:
clang::NamedDecl *DeclForGlobal(llvm::GlobalValue *global);
- //------------------------------------------------------------------
/// Set the constant result variable m_const_result to the provided
/// constant, assuming it can be evaluated. The result variable will be
/// reset to NULL later if the expression has side effects.
///
- /// @param[in] initializer
+ /// \param[in] initializer
/// The constant initializer for the variable.
///
- /// @param[in] name
+ /// \param[in] name
/// The name of the result variable.
///
- /// @param[in] type
+ /// \param[in] type
/// The Clang type of the result variable.
- //------------------------------------------------------------------
void MaybeSetConstantResult(llvm::Constant *initializer,
- const lldb_private::ConstString &name,
+ lldb_private::ConstString name,
lldb_private::TypeFromParser type);
- //------------------------------------------------------------------
/// If the IR represents a cast of a variable, set m_const_result to the
/// result of the cast. The result variable will be reset to
/// NULL latger if the expression has side effects.
///
- /// @param[in] type
+ /// \param[in] type
/// The Clang type of the result variable.
- //------------------------------------------------------------------
void MaybeSetCastResult(lldb_private::TypeFromParser type);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] llvm_function
+ /// \param[in] llvm_function
/// The function currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool CreateResultVariable(llvm::Function &llvm_function);
- //------------------------------------------------------------------
/// A module-level pass to find Objective-C constant strings and
/// transform them to calls to CFStringCreateWithBytes.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Rewrite a single Objective-C constant string.
///
- /// @param[in] NSStr
+ /// \param[in] NSStr
/// The constant NSString to be transformed
///
- /// @param[in] CStr
+ /// \param[in] CStr
/// The constant C string inside the NSString. This will be
/// passed as the bytes argument to CFStringCreateWithBytes.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewriteObjCConstString(llvm::GlobalVariable *NSStr,
llvm::GlobalVariable *CStr);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewriteObjCConstStrings();
- //------------------------------------------------------------------
/// A basic block-level pass to find all Objective-C method calls and
/// rewrite them to use sel_registerName instead of statically allocated
/// selectors. The reason is that the selectors are created on the
@@ -302,59 +261,47 @@ private:
/// section and prepare them. This doesn't happen when code is copied into
/// the target, though, and there's no easy way to induce the runtime to
/// scan them. So instead we get our selectors from sel_registerName.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Replace a single selector reference
///
- /// @param[in] selector_load
+ /// \param[in] selector_load
/// The load of the statically-allocated selector.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewriteObjCSelector(llvm::Instruction *selector_load);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] basic_block
+ /// \param[in] basic_block
/// The basic block currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewriteObjCSelectors(llvm::BasicBlock &basic_block);
- //------------------------------------------------------------------
/// A basic block-level pass to find all Objective-C class references that
/// use the old-style Objective-C runtime and rewrite them to use
/// class_getClass instead of statically allocated class references.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Replace a single old-style class reference
///
- /// @param[in] selector_load
+ /// \param[in] selector_load
/// The load of the statically-allocated selector.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewriteObjCClassReference(llvm::Instruction *class_load);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] basic_block
+ /// \param[in] basic_block
/// The basic block currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewriteObjCClassReferences(llvm::BasicBlock &basic_block);
- //------------------------------------------------------------------
/// A basic block-level pass to find all newly-declared persistent
/// variables and register them with the ClangExprDeclMap. This allows them
/// to be materialized and dematerialized like normal external variables.
@@ -362,182 +309,147 @@ private:
/// locals, so they have an allocation. This pass excises these allocations
/// and makes references look like external references where they will be
/// resolved -- like all other external references -- by ResolveExternals().
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Handle a single allocation of a persistent variable
///
- /// @param[in] persistent_alloc
+ /// \param[in] persistent_alloc
/// The allocation of the persistent variable.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RewritePersistentAlloc(llvm::Instruction *persistent_alloc);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] basic_block
+ /// \param[in] basic_block
/// The basic block currently being processed.
- //------------------------------------------------------------------
bool RewritePersistentAllocs(llvm::BasicBlock &basic_block);
- //------------------------------------------------------------------
/// A function-level pass to find all external variables and functions
/// used in the IR. Each found external variable is added to the struct,
/// and each external function is resolved in place, its call replaced with
/// a call to a function pointer whose value is the address of the function
/// in the target process.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Write an initializer to a memory array of assumed sufficient size.
///
- /// @param[in] data
+ /// \param[in] data
/// A pointer to the data to write to.
///
- /// @param[in] initializer
+ /// \param[in] initializer
/// The initializer itself.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool MaterializeInitializer(uint8_t *data, llvm::Constant *initializer);
- //------------------------------------------------------------------
/// Move an internal variable into the static allocation section.
///
- /// @param[in] global_variable
+ /// \param[in] global_variable
/// The variable.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool MaterializeInternalVariable(llvm::GlobalVariable *global_variable);
- //------------------------------------------------------------------
/// Handle a single externally-defined variable
///
- /// @param[in] value
+ /// \param[in] value
/// The variable.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool MaybeHandleVariable(llvm::Value *value);
- //------------------------------------------------------------------
/// Handle a single externally-defined symbol
///
- /// @param[in] symbol
+ /// \param[in] symbol
/// The symbol.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool HandleSymbol(llvm::Value *symbol);
- //------------------------------------------------------------------
/// Handle a single externally-defined Objective-C class
///
- /// @param[in] classlist_reference
+ /// \param[in] classlist_reference
/// The reference, usually "01L_OBJC_CLASSLIST_REFERENCES_$_n"
/// where n (if present) is an index.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool HandleObjCClass(llvm::Value *classlist_reference);
- //------------------------------------------------------------------
/// Handle all the arguments to a function call
///
- /// @param[in] C
+ /// \param[in] C
/// The call instruction.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool MaybeHandleCallArguments(llvm::CallInst *call_inst);
- //------------------------------------------------------------------
/// Resolve variable references in calls to external functions
///
- /// @param[in] basic_block
+ /// \param[in] basic_block
/// The basic block currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool ResolveCalls(llvm::BasicBlock &basic_block);
- //------------------------------------------------------------------
/// Remove calls to __cxa_atexit, which should never be generated by
/// expressions.
///
- /// @param[in] call_inst
+ /// \param[in] call_inst
/// The call instruction.
///
- /// @return
+ /// \return
/// True if the scan was successful; false if some operation
/// failed
- //------------------------------------------------------------------
bool RemoveCXAAtExit(llvm::BasicBlock &basic_block);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] basic_block
+ /// \param[in] basic_block
/// The function currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool ResolveExternals(llvm::Function &llvm_function);
- //------------------------------------------------------------------
/// A basic block-level pass to excise guard variables from the code.
/// The result for the function is passed through Clang as a static
/// variable. Static variables normally have guard variables to ensure that
/// they are only initialized once.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// Rewrite a load to a guard variable to return constant 0.
///
- /// @param[in] guard_load
+ /// \param[in] guard_load
/// The load instruction to zero out.
- //------------------------------------------------------------------
void TurnGuardLoadIntoZero(llvm::Instruction *guard_load);
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] basic_block
+ /// \param[in] basic_block
/// The basic block currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool RemoveGuards(llvm::BasicBlock &basic_block);
- //------------------------------------------------------------------
/// A function-level pass to make all external variable references
/// point at the correct offsets from the void* passed into the function.
/// ClangExpressionDeclMap::DoStructLayout() must be called beforehand, so
/// that the offsets are valid.
- //------------------------------------------------------------------
- //------------------------------------------------------------------
/// The top-level pass implementation
///
- /// @param[in] llvm_function
+ /// \param[in] llvm_function
/// The function currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool ReplaceVariables(llvm::Function &llvm_function);
/// Flags
@@ -557,18 +469,16 @@ private:
///module.
lldb_private::ClangExpressionDeclMap
*m_decl_map; ///< The DeclMap containing the Decls
- llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function
- ///CFStringCreateWithBytes, cast to
- ///the
- /// appropriate function pointer type
- llvm::Constant *m_sel_registerName; ///< The address of the function
- ///sel_registerName, cast to the
- ///appropriate
- /// function pointer type
- llvm::Constant *m_objc_getClass; ///< The address of the function
- ///objc_getClass, cast to the
- ///appropriate
- /// function pointer type
+ llvm::FunctionCallee
+ m_CFStringCreateWithBytes; ///< The address of the function
+ /// CFStringCreateWithBytes, cast to the
+ /// appropriate function pointer type
+ llvm::FunctionCallee m_sel_registerName; ///< The address of the function
+ /// sel_registerName, cast to the
+ /// appropriate function pointer type
+ llvm::FunctionCallee m_objc_getClass; ///< The address of the function
+ /// objc_getClass, cast to the
+ /// appropriate function pointer type
llvm::IntegerType
*m_intptr_ty; ///< The type of an integer large enough to hold a pointer.
lldb_private::Stream
@@ -589,7 +499,6 @@ private:
///final
/// location of the static allocation.
- //------------------------------------------------------------------
/// UnfoldConstant operates on a constant [Old] which has just been replaced
/// with a value [New]. We assume that new_value has been properly placed
/// early in the function, in front of the first instruction in the entry
@@ -602,12 +511,11 @@ private:
/// instructions replace the constant uses, so UnfoldConstant calls itself
/// recursively for those.
///
- /// @param[in] llvm_function
+ /// \param[in] llvm_function
/// The function currently being processed.
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
class FunctionValueCache {
public:
@@ -631,32 +539,28 @@ private:
FunctionValueCache &entry_instruction_finder,
lldb_private::Stream &error_stream);
- //------------------------------------------------------------------
/// Construct a reference to m_reloc_placeholder with a given type and
/// offset. This typically happens after inserting data into
/// m_data_allocator.
///
- /// @param[in] type
+ /// \param[in] type
/// The type of the value being loaded.
///
- /// @param[in] offset
+ /// \param[in] offset
/// The offset of the value from the base of m_data_allocator.
///
- /// @return
+ /// \return
/// The Constant for the reference, usually a ConstantExpr.
- //------------------------------------------------------------------
llvm::Constant *BuildRelocation(llvm::Type *type, uint64_t offset);
- //------------------------------------------------------------------
/// Commit the allocation in m_data_allocator and use its final location to
/// replace m_reloc_placeholder.
///
- /// @param[in] module
+ /// \param[in] module
/// The module that m_data_allocator resides in
///
- /// @return
+ /// \return
/// True on success; false otherwise
- //------------------------------------------------------------------
bool CompleteDataAllocation();
};
diff --git a/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h
new file mode 100644
index 000000000000..0e959f86fd2a
--- /dev/null
+++ b/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h
@@ -0,0 +1,38 @@
+//===-- ModuleDependencyCollector.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 liblldb_ModuleDependencyCollector_h_
+#define liblldb_ModuleDependencyCollector_h_
+
+#include "lldb/Utility/FileCollector.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+class ModuleDependencyCollectorAdaptor
+ : public clang::ModuleDependencyCollector {
+public:
+ ModuleDependencyCollectorAdaptor(FileCollector &file_collector)
+ : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) {
+ }
+
+ void addFile(llvm::StringRef Filename,
+ llvm::StringRef FileDst = {}) override {
+ m_file_collector.AddFile(Filename);
+ }
+
+ bool insertSeen(llvm::StringRef Filename) override { return false; }
+ void addFileMapping(llvm::StringRef VPath, llvm::StringRef RPath) override {}
+ void writeFileMap() override {}
+
+private:
+ FileCollector &m_file_collector;
+};
+} // namespace lldb_private
+
+#endif