[Expressions] Add support of expressions evaluation in some object's context

Summary:
This patch adds support of expression evaluation in a context of some object.
Consider the following example:
```
struct S {
  int a = 11;
  int b = 12;
};

int main() {
  S s;
  int a = 1;
  int b = 2;
  // We have stopped here
  return 0;
}
```
This patch allows to do something like that:
```
lldb.frame.FindVariable("s").EvaluateExpression("a + b")
```
and the result will be `33` (not `3`) because fields `a` and `b` of `s` will be
used (not locals `a` and `b`).

This is achieved by replacing of `this` type and object for the expression. This
has some limitations: an expression can be evaluated only for values located in
the debuggee process memory (they must have an address of `eAddressTypeLoad`
type).

Reviewers: teemperor, clayborg, jingham, zturner, labath, davide, spyffe, serge-sans-paille

Reviewed By: jingham

Subscribers: abidh, lldb-commits, leonid.mashinskiy

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D55318

llvm-svn: 353149
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 745341b..6e7f11f 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -65,10 +65,12 @@
 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_parser_vars(), m_struct_vars(),
+      m_ctx_obj(ctx_obj) {
   EnableStructVars();
 }
 
@@ -927,6 +929,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)
@@ -1019,6 +1036,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)
@@ -2124,7 +2156,7 @@
 }
 
 void ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
-                                         TypeFromUser &ut,
+                                         const TypeFromUser &ut,
                                          unsigned int current_id) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
@@ -2198,7 +2230,7 @@
 }
 
 void ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
-                                        TypeFromUser &ut,
+                                        const TypeFromUser &ut,
                                         unsigned int current_id) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
index d860979..ac6690d 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -72,11 +72,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,
+      ValueObject *ctx_obj);
 
   //------------------------------------------------------------------
   /// Destructor
@@ -343,6 +348,10 @@
   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
@@ -581,7 +590,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);
 
   //------------------------------------------------------------------
@@ -594,7 +603,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);
 
   //------------------------------------------------------------------
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index e7e9ba9..f967237 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -59,13 +59,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,
+    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()) {
+      m_result_delegate(exe_scope.CalculateTarget()),
+      m_ctx_obj(ctx_obj) {
   switch (m_language) {
   case lldb::eLanguageTypeC_plus_plus:
     m_allow_cxx = true;
@@ -130,7 +132,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) {
@@ -396,7 +418,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)) {
       diagnostic_manager.PutString(eDiagnosticSeverityError,
                                    "couldn't construct expression body");
       return;
@@ -733,7 +756,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(
@@ -776,9 +807,11 @@
 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 *
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
index 836d44e..2f9a723 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -61,7 +61,8 @@
 
     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
@@ -105,11 +106,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,
+                      ValueObject *ctx_obj);
 
   ~ClangUserExpression() override;
 
@@ -153,7 +160,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
@@ -204,6 +212,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.
+  ValueObject *m_ctx_obj;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
index 210ed3c..c15bfa5 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -156,5 +156,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));
 }