aleksandr.urakov updated this revision to Diff 176980.
aleksandr.urakov added a comment.

Thanks for the interest to the feature! I've updated the patch due to the 
comments.

The only problem is that I'm not familiar with Objective C and have no Mac OS 
to test it, so I haven't written the test for Objective C case. I've added the 
"support" of Objective C blindly, so I even not sure that it works correctly. I 
can remove it from the patch (or, may be some person more familiar with the 
theme can check if it is ok?). I'm not sure, is it better to leave a 
preparation of the feature implementation for Objective C or to completely 
remove it?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55318/new/

https://reviews.llvm.org/D55318

Files:
  include/lldb/API/SBValue.h
  include/lldb/Expression/ExpressionSourceCode.h
  include/lldb/Expression/UserExpression.h
  include/lldb/Symbol/ClangASTContext.h
  include/lldb/Symbol/TypeSystem.h
  include/lldb/Target/Target.h
  packages/Python/lldbsuite/test/expression_command/context-object/Makefile
  
packages/Python/lldbsuite/test/expression_command/context-object/TestContextObject.py
  packages/Python/lldbsuite/test/expression_command/context-object/main.cpp
  scripts/interface/SBValue.i
  source/API/SBValue.cpp
  source/Breakpoint/BreakpointLocation.cpp
  source/Breakpoint/Watchpoint.cpp
  source/Commands/CommandObjectExpression.cpp
  source/Expression/ExpressionSourceCode.cpp
  source/Expression/UserExpression.cpp
  source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
  source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
  source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
  source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
  source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
  source/Symbol/ClangASTContext.cpp
  source/Target/Target.cpp

Index: source/Target/Target.cpp
===================================================================
--- source/Target/Target.cpp
+++ source/Target/Target.cpp
@@ -2198,7 +2198,8 @@
 UserExpression *Target::GetUserExpressionForLanguage(
     llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
     Expression::ResultType desired_type,
-    const EvaluateExpressionOptions &options, Status &error) {
+    const EvaluateExpressionOptions &options,
+    const lldb::ValueObjectSP &ctx_obj, Status &error) {
   Status type_system_error;
 
   TypeSystem *type_system =
@@ -2214,7 +2215,7 @@
   }
 
   user_expr = type_system->GetUserExpression(expr, prefix, language,
-                                             desired_type, options);
+                                             desired_type, options, ctx_obj);
   if (!user_expr)
     error.SetErrorStringWithFormat(
         "Could not create an expression for language %s",
@@ -2355,7 +2356,8 @@
 ExpressionResults Target::EvaluateExpression(
     llvm::StringRef expr, ExecutionContextScope *exe_scope,
     lldb::ValueObjectSP &result_valobj_sp,
-    const EvaluateExpressionOptions &options, std::string *fixed_expression) {
+    const EvaluateExpressionOptions &options, std::string *fixed_expression,
+    const lldb::ValueObjectSP &ctx_obj) {
   result_valobj_sp.reset();
 
   ExpressionResults execution_results = eExpressionSetupError;
@@ -2396,7 +2398,9 @@
     execution_results = UserExpression::Evaluate(exe_ctx, options, expr, prefix,
                                                  result_valobj_sp, error,
                                                  0, // Line Number
-                                                 fixed_expression);
+                                                 fixed_expression,
+                                                 nullptr, // Module
+                                                 ctx_obj);
   }
 
   m_suppress_stop_hooks = old_suppress_value;
Index: source/Symbol/ClangASTContext.cpp
===================================================================
--- source/Symbol/ClangASTContext.cpp
+++ source/Symbol/ClangASTContext.cpp
@@ -10294,13 +10294,14 @@
 UserExpression *ClangASTContextForExpressions::GetUserExpression(
     llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
     Expression::ResultType desired_type,
-    const EvaluateExpressionOptions &options) {
+    const EvaluateExpressionOptions &options,
+    const lldb::ValueObjectSP &ctx_obj) {
   TargetSP target_sp = m_target_wp.lock();
   if (!target_sp)
     return nullptr;
 
   return new ClangUserExpression(*target_sp.get(), expr, prefix, language,
-                                 desired_type, options);
+                                 desired_type, options, ctx_obj);
 }
 
 FunctionCaller *ClangASTContextForExpressions::GetFunctionCaller(
Index: source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -157,5 +157,6 @@
 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));
 }
Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -62,7 +62,8 @@
 
     void ResetDeclMap(ExecutionContext &exe_ctx,
                       Materializer::PersistentVariableDelegate &result_delegate,
-                      bool keep_result_in_memory);
+                      bool keep_result_in_memory,
+                      const lldb::ValueObjectSP &ctx_obj);
 
     //------------------------------------------------------------------
     /// Return the object that the parser should allow to access ASTs. May be
@@ -106,11 +107,17 @@
   /// @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,
+                      const lldb::ValueObjectSP &ctx_obj);
 
   ~ClangUserExpression() override;
 
@@ -154,7 +161,8 @@
                     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
@@ -205,6 +213,10 @@
   /// 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.
+  lldb::ValueObjectSP m_ctx_obj;
 };
 
 } // namespace lldb_private
Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -60,13 +60,15 @@
 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,
+    const lldb::ValueObjectSP &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()) {
+      m_result_delegate(exe_scope.CalculateTarget()),
+      m_ctx_obj(ctx_obj) {
   switch (m_language) {
   case lldb::eLanguageTypeC_plus_plus:
     m_allow_cxx = true;
@@ -131,7 +133,27 @@
     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) {
@@ -397,7 +419,8 @@
       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.empty())) {
       diagnostic_manager.PutString(eDiagnosticSeverityError,
                                    "couldn't construct expression body");
       return;
@@ -734,7 +757,15 @@
 
     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 +808,11 @@
 void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
     ExecutionContext &exe_ctx,
     Materializer::PersistentVariableDelegate &delegate,
-    bool keep_result_in_memory) {
+    bool keep_result_in_memory,
+    const lldb::ValueObjectSP &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 *
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -73,11 +73,16 @@
   ///
   /// @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,
+      const lldb::ValueObjectSP &ctx_obj);
 
   //------------------------------------------------------------------
   /// Destructor
@@ -344,6 +349,10 @@
   Materializer::PersistentVariableDelegate
       *m_result_delegate; ///< If non-NULL, used to report expression results to
                           ///ClangUserExpression.
+  lldb::ValueObjectSP 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
@@ -582,7 +591,7 @@
   /// @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);
 
   //------------------------------------------------------------------
@@ -595,7 +604,7 @@
   /// @param[in] type
   ///     The type for *this.
   //------------------------------------------------------------------
-  void AddThisType(NameSearchContext &context, TypeFromUser &type,
+  void AddThisType(NameSearchContext &context, const TypeFromUser &type,
                    unsigned int current_id);
 
   //------------------------------------------------------------------
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -66,10 +66,12 @@
 ClangExpressionDeclMap::ClangExpressionDeclMap(
     bool keep_result_in_memory,
     Materializer::PersistentVariableDelegate *result_delegate,
-    ExecutionContext &exe_ctx)
+    ExecutionContext &exe_ctx,
+    const lldb::ValueObjectSP &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_parser_vars(), m_struct_vars(),
+      m_ctx_obj(ctx_obj) {
   EnableStructVars();
 }
 
@@ -928,6 +930,21 @@
     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)
@@ -1020,6 +1037,21 @@
 
     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)
@@ -2125,7 +2157,7 @@
 }
 
 void ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
-                                         TypeFromUser &ut,
+                                         const TypeFromUser &ut,
                                          unsigned int current_id) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
@@ -2199,7 +2231,7 @@
 }
 
 void ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
-                                        TypeFromUser &ut,
+                                        const TypeFromUser &ut,
                                         unsigned int current_id) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
Index: source/Expression/UserExpression.cpp
===================================================================
--- source/Expression/UserExpression.cpp
+++ source/Expression/UserExpression.cpp
@@ -141,10 +141,23 @@
     ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options,
     llvm::StringRef expr, llvm::StringRef prefix,
     lldb::ValueObjectSP &result_valobj_sp, Status &error, uint32_t line_offset,
-    std::string *fixed_expression, lldb::ModuleSP *jit_module_sp_ptr) {
+    std::string *fixed_expression, lldb::ModuleSP *jit_module_sp_ptr,
+    const lldb::ValueObjectSP &ctx_obj) {
   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS |
                                                   LIBLLDB_LOG_STEP));
 
+  if (ctx_obj) {
+    static unsigned const ctx_type_mask =
+        lldb::TypeFlags::eTypeIsClass | lldb::TypeFlags::eTypeIsStructUnion;
+    if (!(ctx_obj->GetTypeInfo() & ctx_type_mask)) {
+      if (log)
+        log->Printf("== [UserExpression::Evaluate] Passed a context object of "
+                    "an invalid type, can't run expressions.");
+      error.SetErrorString("a context object of an invalid type passed");
+      return lldb::eExpressionSetupError;
+    }
+  }
+
   lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy();
   lldb::LanguageType language = options.GetLanguage();
   const ResultType desired_type = options.DoesCoerceToId()
@@ -209,7 +222,8 @@
 
   lldb::UserExpressionSP user_expression_sp(
       target->GetUserExpressionForLanguage(expr, full_prefix, language,
-                                           desired_type, options, error));
+                                           desired_type, options, ctx_obj,
+                                           error));
   if (error.Fail()) {
     if (log)
       log->Printf("== [UserExpression::Evaluate] Getting expression: %s ==",
@@ -254,7 +268,8 @@
       lldb::UserExpressionSP fixed_expression_sp(
           target->GetUserExpressionForLanguage(fixed_expression->c_str(),
                                                full_prefix, language,
-                                               desired_type, options, error));
+                                               desired_type, options, ctx_obj,
+                                               error));
       DiagnosticManager fixed_diagnostic_manager;
       parse_success = fixed_expression_sp->Parse(
           fixed_diagnostic_manager, exe_ctx, execution_policy,
Index: source/Expression/ExpressionSourceCode.cpp
===================================================================
--- source/Expression/ExpressionSourceCode.cpp
+++ source/Expression/ExpressionSourceCode.cpp
@@ -182,7 +182,8 @@
 bool ExpressionSourceCode::GetText(std::string &text,
                                    lldb::LanguageType wrapping_language,
                                    bool static_method,
-                                   ExecutionContext &exe_ctx) const {
+                                   ExecutionContext &exe_ctx,
+                                   bool add_locals) const {
   const char *target_specific_defines = "typedef signed char BOOL;\n";
   std::string module_macros;
 
@@ -255,12 +256,13 @@
       }
     }
 
-    ConstString object_name;
-    if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) {
-      if (target->GetInjectLocalVariables(&exe_ctx)) {
-        lldb::VariableListSP var_list_sp =
-            frame->GetInScopeVariableList(false, true);
-        AddLocalVariableDecls(var_list_sp, lldb_local_var_decls);
+    if (add_locals) {
+      if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) {
+        if (target->GetInjectLocalVariables(&exe_ctx)) {
+          lldb::VariableListSP var_list_sp =
+              frame->GetInScopeVariableList(false, true);
+          AddLocalVariableDecls(var_list_sp, lldb_local_var_decls);
+        }
       }
     }
   }
Index: source/Commands/CommandObjectExpression.cpp
===================================================================
--- source/Commands/CommandObjectExpression.cpp
+++ source/Commands/CommandObjectExpression.cpp
@@ -364,7 +364,7 @@
   Status error;
   lldb::UserExpressionSP expr(target->GetUserExpressionForLanguage(
       code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
-      options, error));
+      options, nullptr, error));
   if (error.Fail())
     return 0;
 
Index: source/Breakpoint/Watchpoint.cpp
===================================================================
--- source/Breakpoint/Watchpoint.cpp
+++ source/Breakpoint/Watchpoint.cpp
@@ -283,7 +283,8 @@
     Status error;
     m_condition_ap.reset(m_target.GetUserExpressionForLanguage(
         condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
-        UserExpression::eResultTypeAny, EvaluateExpressionOptions(), error));
+        UserExpression::eResultTypeAny, EvaluateExpressionOptions(),
+        nullptr, error));
     if (error.Fail()) {
       // FIXME: Log something...
       m_condition_ap.reset();
Index: source/Breakpoint/BreakpointLocation.cpp
===================================================================
--- source/Breakpoint/BreakpointLocation.cpp
+++ source/Breakpoint/BreakpointLocation.cpp
@@ -256,7 +256,7 @@
 
     m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
         condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
-        EvaluateExpressionOptions(), error));
+        EvaluateExpressionOptions(), nullptr, error));
     if (error.Fail()) {
       if (log)
         log->Printf("Error getting condition expression: %s.",
Index: source/API/SBValue.cpp
===================================================================
--- source/API/SBValue.cpp
+++ source/API/SBValue.cpp
@@ -1298,6 +1298,83 @@
   return false;
 }
 
+lldb::SBValue SBValue::EvaluateExpression(const char* expr) const {
+  ValueLocker locker;
+  lldb::ValueObjectSP value_sp(GetSP(locker));
+  if (!value_sp)
+    return SBValue();
+
+  lldb::TargetSP target_sp = value_sp->GetTargetSP();
+  if (!target_sp)
+    return SBValue();
+
+  lldb::SBExpressionOptions options;
+  options.SetFetchDynamicValue(target_sp->GetPreferDynamicValue());
+  options.SetUnwindOnError(true);
+  options.SetIgnoreBreakpoints(true);
+
+  return EvaluateExpression(expr, options);
+}
+
+lldb::SBValue
+SBValue::EvaluateExpression(const char* expr,
+                            const SBExpressionOptions& options) const {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+
+  if (!expr || expr[0] == '\0') {
+    if (log)
+      log->Printf(
+          "SBValue::EvaluateExpression called with an empty expression");
+    return SBValue();
+  }
+
+  if (log)
+    log->Printf("SBValue()::EvaluateExpression (expr=\"%s\")...", expr);
+
+  ValueLocker locker;
+  lldb::ValueObjectSP value_sp(GetSP(locker));
+  if (!value_sp) {
+    if (log)
+      log->Printf("SBValue::EvaluateExpression () => error: could not "
+                  "reconstruct value object for this SBValue");
+    return SBValue();
+  }
+
+  lldb::TargetSP target_sp = value_sp->GetTargetSP();
+  if (!target_sp) {
+    if (log)
+      log->Printf("SBValue::EvaluateExpression () => error: could not "
+                  "retrieve target");
+    return SBValue();
+  }
+
+  std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
+  ExecutionContext exe_ctx(target_sp.get());
+
+  StackFrame *frame = exe_ctx.GetFramePtr();
+  if (!frame) {
+    if (log)
+      log->Printf("SBValue::EvaluateExpression () => error: could not "
+                  "retrieve current stack frame");
+    return SBValue();
+  }
+
+  ValueObjectSP res_val_sp;
+  ExpressionResults expr_res =
+      target_sp->EvaluateExpression(expr, frame, res_val_sp, options.ref(),
+                                    nullptr, value_sp);
+
+  if (log)
+    log->Printf("SBValue(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) "
+                "(execution result=%d)",
+                static_cast<void *>(value_sp.get()), expr,
+                static_cast<void *>(res_val_sp.get()), expr_res);
+
+  SBValue result;
+  result.SetSP(res_val_sp, options.GetFetchDynamicValue());
+  return result;
+}
+
 bool SBValue::GetDescription(SBStream &description) {
   Stream &strm = description.ref();
 
Index: scripts/interface/SBValue.i
===================================================================
--- scripts/interface/SBValue.i
+++ scripts/interface/SBValue.i
@@ -449,7 +449,14 @@
     ) GetExpressionPath;
     bool
     GetExpressionPath (lldb::SBStream &description, bool qualify_cxx_base_classes);
-    
+
+    lldb::SBValue
+    EvaluateExpression(const char *expr) const;
+
+    lldb::SBValue
+    EvaluateExpression(const char *expr,
+                       const SBExpressionOptions &options) const;
+
     %pythoncode %{
         def __get_dynamic__ (self):
             '''Helper function for the "SBValue.dynamic" property.'''
Index: packages/Python/lldbsuite/test/expression_command/context-object/main.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/context-object/main.cpp
@@ -0,0 +1,46 @@
+namespace cpp_namespace {
+  struct CppStruct {
+    int field = 1111;
+
+    int function() {
+      return 2222;
+    }
+  };
+
+  union CppUnion {
+    char field_char;
+    short field_short;
+    int field_int;
+  };
+
+  CppStruct GetCppStruct() {
+    return CppStruct();
+  }
+
+  CppStruct global;
+
+  CppStruct *GetCppStructPtr() {
+    return &global;
+  }
+}
+
+int global = 3333;
+
+int main()
+{
+  cpp_namespace::CppStruct cpp_struct = cpp_namespace::GetCppStruct();
+  cpp_struct.function();
+
+  int field = 4444;
+
+  cpp_namespace::CppUnion cpp_union;
+  cpp_union.field_int = 5555;
+
+  int cpp_scalar = 6666;
+
+  cpp_namespace::CppStruct cpp_array[16];
+
+  cpp_namespace::CppStruct *cpp_pointer = cpp_namespace::GetCppStructPtr();
+
+  return 0; // Break here
+}
Index: packages/Python/lldbsuite/test/expression_command/context-object/TestContextObject.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/context-object/TestContextObject.py
@@ -0,0 +1,145 @@
+"""
+Tests expression evaluation in context of an object.
+"""
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class ContextObjectTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def test_context_object(self):
+        """Tests expression evaluation in context of an object."""
+        self.build()
+
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, '// Break here', self.main_source_spec)
+        frame = thread.GetFrameAtIndex(0)
+
+        #
+        # Test C++ struct variable
+        #
+
+        obj_val = frame.FindVariable("cpp_struct")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test an empty expression evaluation
+        value = obj_val.EvaluateExpression("")
+        self.assertFalse(value.IsValid())
+        self.assertFalse(value.GetError().Success())
+
+        # Test retrieveing of a field (not a local with the same name)
+        value = obj_val.EvaluateExpression("field")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 1111)
+
+        # Test functions evaluation
+        value = obj_val.EvaluateExpression("function()")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 2222)
+
+        # Test that we retrieve the right global
+        value = obj_val.EvaluateExpression("global.field")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 1111)
+
+        #
+        # Test C++ union variable
+        #
+
+        obj_val = frame.FindVariable("cpp_union")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test retrieveing of a field
+        value = obj_val.EvaluateExpression("field_int")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 5555)
+
+        #
+        # Test C++ scalar
+        #
+
+        obj_val = frame.FindVariable("cpp_scalar")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test an expression evaluation
+        value = obj_val.EvaluateExpression("1")
+        self.assertFalse(value.IsValid())
+        self.assertFalse(value.GetError().Success())
+
+        #
+        # Test C++ array
+        #
+
+        obj_val = frame.FindVariable("cpp_array")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test an expression evaluation
+        value = obj_val.EvaluateExpression("1")
+        self.assertFalse(value.IsValid())
+        self.assertFalse(value.GetError().Success())
+
+        # Test retrieveing of an element's field
+        value = obj_val.GetValueForExpressionPath("[7]").EvaluateExpression("field")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 1111)
+
+        #
+        # Test C++ pointer
+        #
+
+        obj_val = frame.FindVariable("cpp_pointer")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test an expression evaluation
+        value = obj_val.EvaluateExpression("1")
+        self.assertFalse(value.IsValid())
+        self.assertFalse(value.GetError().Success())
+
+        # Test retrieveing of a dereferenced object's field
+        value = obj_val.Dereference().EvaluateExpression("field")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 1111)
+
+        #
+        # Test C++ computation result
+        #
+
+        obj_val = frame.EvaluateExpression("cpp_namespace::GetCppStruct()")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test an expression evaluation
+        value = obj_val.EvaluateExpression("1")
+        self.assertTrue(value.IsValid())
+        self.assertFalse(value.GetError().Success())
+
+        #
+        # Test C++ computation result located in debuggee memory
+        #
+
+        obj_val = frame.EvaluateExpression("cpp_namespace::GetCppStructPtr()")
+        self.assertTrue(obj_val.IsValid())
+
+        # Test an expression evaluation
+        value = obj_val.EvaluateExpression("1")
+        self.assertFalse(value.IsValid())
+        self.assertFalse(value.GetError().Success())
+
+        # Test retrieveing of a dereferenced object's field
+        value = obj_val.Dereference().EvaluateExpression("field")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 1111)
+
+    def setUp(self):
+        TestBase.setUp(self)
+
+        self.main_source = "main.cpp"
+        self.main_source_spec = lldb.SBFileSpec(self.main_source)
Index: packages/Python/lldbsuite/test/expression_command/context-object/Makefile
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/context-object/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
Index: include/lldb/Target/Target.h
===================================================================
--- include/lldb/Target/Target.h
+++ include/lldb/Target/Target.h
@@ -1038,7 +1038,8 @@
   UserExpression *GetUserExpressionForLanguage(
       llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
       Expression::ResultType desired_type,
-      const EvaluateExpressionOptions &options, Status &error);
+      const EvaluateExpressionOptions &options,
+      const lldb::ValueObjectSP &ctx_obj, Status &error);
 
   // Creates a FunctionCaller for the given language, the rest of the
   // parameters have the same meaning as for the FunctionCaller constructor.
@@ -1102,7 +1103,8 @@
       llvm::StringRef expression, ExecutionContextScope *exe_scope,
       lldb::ValueObjectSP &result_valobj_sp,
       const EvaluateExpressionOptions &options = EvaluateExpressionOptions(),
-      std::string *fixed_expression = nullptr);
+      std::string *fixed_expression = nullptr,
+      const lldb::ValueObjectSP &ctx_obj = lldb::ValueObjectSP());
 
   lldb::ExpressionVariableSP GetPersistentVariable(const ConstString &name);
 
Index: include/lldb/Symbol/TypeSystem.h
===================================================================
--- include/lldb/Symbol/TypeSystem.h
+++ include/lldb/Symbol/TypeSystem.h
@@ -449,7 +449,8 @@
   GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
                     lldb::LanguageType language,
                     Expression::ResultType desired_type,
-                    const EvaluateExpressionOptions &options) {
+                    const EvaluateExpressionOptions &options,
+                    const lldb::ValueObjectSP &ctx_obj) {
     return nullptr;
   }
 
Index: include/lldb/Symbol/ClangASTContext.h
===================================================================
--- include/lldb/Symbol/ClangASTContext.h
+++ include/lldb/Symbol/ClangASTContext.h
@@ -1053,7 +1053,8 @@
   GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
                     lldb::LanguageType language,
                     Expression::ResultType desired_type,
-                    const EvaluateExpressionOptions &options) override;
+                    const EvaluateExpressionOptions &options,
+                    const lldb::ValueObjectSP &ctx_obj) override;
 
   FunctionCaller *GetFunctionCaller(const CompilerType &return_type,
                                     const Address &function_address,
Index: include/lldb/Expression/UserExpression.h
===================================================================
--- include/lldb/Expression/UserExpression.h
+++ include/lldb/Expression/UserExpression.h
@@ -273,6 +273,16 @@
   /// @param[out] jit_module_sp_ptr
   ///     If non-nullptr, used to persist the generated IR module.
   ///
+  /// @param[in] ctx_obj
+  ///     If specified, then the expression will be evaluated in the context of
+  ///     this object. It means that the context object's address will be
+  ///     treated as `this` for the expression (the expression will be
+  ///     evaluated as if it was inside of a method of the context object's
+  ///     class, and its `this` parameter were pointing to the context object).
+  ///     The parameter makes sense for class and union types only.
+  ///     Currently there is a limitation: the context object must be located
+  ///     in the debuggee process' memory (and have the load address).
+  ///
   /// @result
   ///      A Process::ExpressionResults value.  eExpressionCompleted for
   ///      success.
@@ -282,7 +292,8 @@
            llvm::StringRef expr_cstr, llvm::StringRef expr_prefix,
            lldb::ValueObjectSP &result_valobj_sp, Status &error,
            uint32_t line_offset = 0, std::string *fixed_expression = nullptr,
-           lldb::ModuleSP *jit_module_sp_ptr = nullptr);
+           lldb::ModuleSP *jit_module_sp_ptr = nullptr,
+           const lldb::ValueObjectSP &ctx_obj = lldb::ValueObjectSP());
 
   static const Status::ValueType kNoResult =
       0x1001; ///< ValueObject::GetError() returns this if there is no result
Index: include/lldb/Expression/ExpressionSourceCode.h
===================================================================
--- include/lldb/Expression/ExpressionSourceCode.h
+++ include/lldb/Expression/ExpressionSourceCode.h
@@ -37,7 +37,8 @@
   const char *GetName() const { return m_name.c_str(); }
 
   bool GetText(std::string &text, lldb::LanguageType wrapping_language,
-               bool static_method, ExecutionContext &exe_ctx) const;
+               bool static_method, ExecutionContext &exe_ctx,
+               bool add_locals) 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
Index: include/lldb/API/SBValue.h
===================================================================
--- include/lldb/API/SBValue.h
+++ include/lldb/API/SBValue.h
@@ -307,6 +307,10 @@
   bool GetExpressionPath(lldb::SBStream &description,
                          bool qualify_cxx_base_classes);
 
+  lldb::SBValue EvaluateExpression(const char *expr) const;
+  lldb::SBValue EvaluateExpression(const char *expr,
+                                   const SBExpressionOptions &options) const;
+
   SBValue(const lldb::ValueObjectSP &value_sp);
 
   //------------------------------------------------------------------
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to