kastiglione created this revision.
Herald added a subscriber: ChuanqiXu.
Herald added a project: All.
kastiglione updated this revision to Diff 502753.
kastiglione added a comment.
kastiglione edited the summary of this revision.
kastiglione added reviewers: aprantl, Michael137, jingham.
kastiglione published this revision for review.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Add tests; rebase


The `v` (`frame variable`) command can access ivars/fields of `this` or `self`. 
This
change relaxes the criteria for finding `this`/`self`.

There are cases where a `this`/`self` variable does exist, but are cases in 
which `v` did not
support direct access of ivars -- meaning the user would have to type 
`this->field` or
`self->_ivar` to access. This change allows those cases to also work without 
explicitly
dereferencing `this`/`self`.

For example:

  __weak Type *weakSelf = self;
  void (^block)() = ^{
     Type *self = weakSelf; // Re-establish strong reference.
     // ...
  };

In this case, `self` exists but `v` wouldn't use it.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145276

Files:
  lldb/include/lldb/Symbol/CompilerDeclContext.h
  lldb/include/lldb/Symbol/SymbolContext.h
  lldb/include/lldb/Symbol/TypeSystem.h
  lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
  lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
  lldb/source/Symbol/CompilerDeclContext.cpp
  lldb/source/Symbol/SymbolContext.cpp
  lldb/source/Target/StackFrame.cpp
  lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile
  
lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
  lldb/test/API/commands/frame/var/direct-ivar/objc/main.m

Index: lldb/test/API/commands/frame/var/direct-ivar/objc/main.m
===================================================================
--- lldb/test/API/commands/frame/var/direct-ivar/objc/main.m
+++ lldb/test/API/commands/frame/var/direct-ivar/objc/main.m
@@ -7,13 +7,25 @@
 @end
 
 @implementation Classic
-- (int)fun {
+- (void)fun {
   // check self
 }
+
+- (void)run {
+  __weak Classic *weakSelf = self;
+  ^{
+    Classic *self = weakSelf;
+    // check idiomatic self
+
+    // Use `self` to extend its lifetime (for lldb to inspect the variable).
+    [self copy];
+  }();
+}
 @end
 
 int main() {
   Classic *c = [Classic new];
   c->_ivar = 30;
   [c fun];
+  [c run];
 }
Index: lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
===================================================================
--- lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
+++ lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
@@ -10,3 +10,11 @@
         self.build()
         lldbutil.run_to_source_breakpoint(self, "// check self", lldb.SBFileSpec("main.m"))
         self.expect("frame variable _ivar", startstr="(int) _ivar = 30")
+
+    @skipUnlessDarwin
+    def test_objc_self_capture_idiom(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// check idiomatic self", lldb.SBFileSpec("main.m"))
+        self.expect("frame variable weakSelf", startstr="(Classic *) weakSelf = 0x")
+        self.expect("frame variable self", startstr="(Classic *) self = 0x")
+        self.expect("frame variable _ivar", startstr="(int) _ivar = 30")
Index: lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile
===================================================================
--- lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile
+++ lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile
@@ -1,2 +1,4 @@
 OBJC_SOURCES := main.m
+CFLAGS_EXTRAS := -fblocks -fobjc-arc
+LD_EXTRAS := -lobjc
 include Makefile.rules
Index: lldb/source/Target/StackFrame.cpp
===================================================================
--- lldb/source/Target/StackFrame.cpp
+++ lldb/source/Target/StackFrame.cpp
@@ -567,23 +567,20 @@
     // Check for direct ivars access which helps us with implicit access to
     // ivars using "this" or "self".
     GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock);
-    ConstString method_object_name;
-    if (m_sc.GetFunctionMethodInfo(method_object_name)) {
-      if (method_object_name) {
-        var_sp = variable_list->FindVariable(method_object_name);
-        if (var_sp) {
-          separator_idx = 0;
-          if (Type *var_type = var_sp->GetType())
-            if (auto compiler_type = var_type->GetForwardCompilerType())
-              if (!compiler_type.IsPointerType())
-                var_expr_storage = ".";
+    if (auto instance_var_name = m_sc.GetInstanceVariableName()) {
+      var_sp = variable_list->FindVariable(instance_var_name);
+      if (var_sp) {
+        separator_idx = 0;
+        if (Type *var_type = var_sp->GetType())
+          if (auto compiler_type = var_type->GetForwardCompilerType())
+            if (!compiler_type.IsPointerType())
+              var_expr_storage = ".";
 
-          if (var_expr_storage.empty())
-            var_expr_storage = "->";
-          var_expr_storage += var_expr;
-          var_expr = var_expr_storage;
-          synthetically_added_instance_object = true;
-        }
+        if (var_expr_storage.empty())
+          var_expr_storage = "->";
+        var_expr_storage += var_expr;
+        var_expr = var_expr_storage;
+        synthetically_added_instance_object = true;
       }
     }
   }
Index: lldb/source/Symbol/SymbolContext.cpp
===================================================================
--- lldb/source/Symbol/SymbolContext.cpp
+++ lldb/source/Symbol/SymbolContext.cpp
@@ -539,14 +539,16 @@
   return nullptr;
 }
 
-bool SymbolContext::GetFunctionMethodInfo(ConstString &language_object_name) {
-  Block *function_block = GetFunctionBlock();
-  if (function_block) {
-    CompilerDeclContext decl_ctx = function_block->GetDeclContext();
-    if (decl_ctx)
-      return decl_ctx.IsClassMethod(&language_object_name);
-  }
-  return false;
+ConstString SymbolContext::GetInstanceVariableName() {
+  if (Block *function_block = GetFunctionBlock())
+    if (CompilerDeclContext decl_ctx = function_block->GetDeclContext()) {
+      auto language = decl_ctx.GetLanguage();
+      if (language == eLanguageTypeUnknown)
+        language = GetLanguage();
+      return decl_ctx.GetInstanceVariableName(language);
+    }
+
+  return {};
 }
 
 void SymbolContext::SortTypeList(TypeMap &type_map, TypeList &type_list) const {
Index: lldb/source/Symbol/CompilerDeclContext.cpp
===================================================================
--- lldb/source/Symbol/CompilerDeclContext.cpp
+++ lldb/source/Symbol/CompilerDeclContext.cpp
@@ -34,13 +34,25 @@
   return ConstString();
 }
 
-bool CompilerDeclContext::IsClassMethod(ConstString *language_object_name_ptr) {
+bool CompilerDeclContext::IsClassMethod() {
   if (IsValid())
-    return m_type_system->DeclContextIsClassMethod(m_opaque_decl_ctx,
-                                                   language_object_name_ptr);
+    return m_type_system->DeclContextIsClassMethod(m_opaque_decl_ctx);
   return false;
 }
 
+lldb::LanguageType CompilerDeclContext::GetLanguage() {
+  if (IsValid())
+    return m_type_system->DeclContextGetLanguage(m_opaque_decl_ctx);
+  return {};
+}
+
+ConstString
+CompilerDeclContext::GetInstanceVariableName(lldb::LanguageType language) {
+  if (IsValid())
+    return m_type_system->GetInstanceVariableName(language);
+  return {};
+}
+
 bool CompilerDeclContext::IsContainedInLookup(CompilerDeclContext other) const {
   if (!IsValid())
     return false;
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
===================================================================
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -579,12 +579,13 @@
 
   ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override;
 
-  bool DeclContextIsClassMethod(void *opaque_decl_ctx,
-                                ConstString *language_object_name_ptr) override;
+  bool DeclContextIsClassMethod(void *opaque_decl_ctx) override;
 
   bool DeclContextIsContainedInLookup(void *opaque_decl_ctx,
                                       void *other_opaque_decl_ctx) override;
 
+  lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) override;
+
   // Clang specific clang::DeclContext functions
 
   static clang::DeclContext *
@@ -710,6 +711,8 @@
 
   bool SupportsLanguage(lldb::LanguageType language) override;
 
+  ConstString GetInstanceVariableName(lldb::LanguageType language) override;
+
   static std::optional<std::string> GetCXXClassName(const CompilerType &type);
 
   // Type Completion
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===================================================================
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -8,6 +8,8 @@
 
 #include "TypeSystemClang.h"
 
+#include "clang/AST/DeclBase.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/FormatAdapters.h"
 #include "llvm/Support/FormatVariadic.h"
 
@@ -3725,6 +3727,22 @@
   return TypeSystemClangSupportsLanguage(language);
 }
 
+ConstString
+TypeSystemClang::GetInstanceVariableName(lldb::LanguageType language) {
+  switch (language) {
+  case LanguageType::eLanguageTypeC_plus_plus:
+  case LanguageType::eLanguageTypeC_plus_plus_03:
+  case LanguageType::eLanguageTypeC_plus_plus_11:
+  case LanguageType::eLanguageTypeC_plus_plus_14:
+    return ConstString("this");
+  case LanguageType::eLanguageTypeObjC:
+  case LanguageType::eLanguageTypeObjC_plus_plus:
+    return ConstString("self");
+  default:
+    return {};
+  }
+}
+
 std::optional<std::string>
 TypeSystemClang::GetCXXClassName(const CompilerType &type) {
   if (!type)
@@ -9750,32 +9768,21 @@
   return ConstString();
 }
 
-bool TypeSystemClang::DeclContextIsClassMethod(
-    void *opaque_decl_ctx, ConstString *language_object_name_ptr) {
-  if (opaque_decl_ctx) {
-    clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
-    if (ObjCMethodDecl *objc_method =
-            llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) {
-      if (objc_method->isInstanceMethod())
-        if (language_object_name_ptr)
-          language_object_name_ptr->SetCString("self");
-      return true;
-    } else if (CXXMethodDecl *cxx_method =
-                   llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) {
-      if (cxx_method->isInstance())
-        if (language_object_name_ptr)
-          language_object_name_ptr->SetCString("this");
-      return true;
-    } else if (clang::FunctionDecl *function_decl =
-                   llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
-      ClangASTMetadata *metadata = GetMetadata(function_decl);
-      if (metadata && metadata->HasObjectPtr()) {
-        if (language_object_name_ptr)
-          language_object_name_ptr->SetCString(metadata->GetObjectPtrName());
-        return true;
-      }
-    }
+bool TypeSystemClang::DeclContextIsClassMethod(void *opaque_decl_ctx) {
+  if (!opaque_decl_ctx)
+    return false;
+
+  clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
+  if (llvm::isa<clang::ObjCMethodDecl>(decl_ctx)) {
+    return true;
+  } else if (llvm::isa<clang::CXXMethodDecl>(decl_ctx)) {
+    return true;
+  } else if (clang::FunctionDecl *fun_decl =
+                 llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
+    if (ClangASTMetadata *metadata = GetMetadata(fun_decl))
+      return metadata->HasObjectPtr();
   }
+
   return false;
 }
 
@@ -9796,6 +9803,24 @@
   return false;
 }
 
+lldb::LanguageType
+TypeSystemClang::DeclContextGetLanguage(void *opaque_decl_ctx) {
+  if (!opaque_decl_ctx)
+    return eLanguageTypeUnknown;
+
+  auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
+  if (llvm::isa<clang::ObjCMethodDecl>(decl_ctx)) {
+    return eLanguageTypeObjC;
+  } else if (llvm::isa<clang::CXXMethodDecl>(decl_ctx)) {
+    return eLanguageTypeC_plus_plus;
+  } else if (auto *fun_decl = llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
+    if (ClangASTMetadata *metadata = GetMetadata(fun_decl))
+      return metadata->GetObjectPtrLanguage();
+  }
+
+  return eLanguageTypeUnknown;
+}
+
 static bool IsClangDeclContext(const CompilerDeclContext &dc) {
   return dc.IsValid() && isa<TypeSystemClang>(dc.GetTypeSystem());
 }
Index: lldb/include/lldb/Symbol/TypeSystem.h
===================================================================
--- lldb/include/lldb/Symbol/TypeSystem.h
+++ lldb/include/lldb/Symbol/TypeSystem.h
@@ -127,13 +127,13 @@
   virtual ConstString
   DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) = 0;
 
-  virtual bool
-  DeclContextIsClassMethod(void *opaque_decl_ctx,
-                           ConstString *language_object_name_ptr) = 0;
+  virtual bool DeclContextIsClassMethod(void *opaque_decl_ctx) = 0;
 
   virtual bool DeclContextIsContainedInLookup(void *opaque_decl_ctx,
                                               void *other_opaque_decl_ctx) = 0;
 
+  virtual lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) = 0;
+
   // Tests
 #ifndef NDEBUG
   /// Verify the integrity of the type to catch CompilerTypes that mix
@@ -202,6 +202,10 @@
   // TypeSystems can support more than one language
   virtual bool SupportsLanguage(lldb::LanguageType language) = 0;
 
+  /// The name of the variable used for explicitly accessing data scoped to the
+  /// current instance (or type). C++ uses "this", ObjC uses "self".
+  virtual ConstString GetInstanceVariableName(lldb::LanguageType language) = 0;
+
   // Type Completion
 
   virtual bool GetCompleteType(lldb::opaque_compiler_type_t type) = 0;
Index: lldb/include/lldb/Symbol/SymbolContext.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolContext.h
+++ lldb/include/lldb/Symbol/SymbolContext.h
@@ -245,17 +245,13 @@
   ///     represented by this symbol context object, nullptr otherwise.
   Block *GetFunctionBlock();
 
-  /// If this symbol context represents a function that is a method, return
-  /// true and provide information about the method.
+  /// Determines the name of the instance variable for the this decl context.
   ///
-  /// \param[out] language_object_name
-  ///     If \b true is returned, the name of the artificial variable
-  ///     for the language ("this" for C++, "self" for ObjC).
+  /// For C++ the name is "this", for Objective-C the name is "self".
   ///
   /// \return
-  ///     \b True if this symbol context represents a function that
-  ///     is a method of a class, \b false otherwise.
-  bool GetFunctionMethodInfo(ConstString &language_object_name);
+  ///     Returns a string for the name of the instance variable.
+  ConstString GetInstanceVariableName();
 
   /// Sorts the types in TypeMap according to SymbolContext to TypeList
   ///
Index: lldb/include/lldb/Symbol/CompilerDeclContext.h
===================================================================
--- lldb/include/lldb/Symbol/CompilerDeclContext.h
+++ lldb/include/lldb/Symbol/CompilerDeclContext.h
@@ -61,15 +61,21 @@
 
   /// Checks if this decl context represents a method of a class.
   ///
-  /// \param[out] language_object_name_ptr
-  ///     If non NULL and \b true is returned from this function,
-  ///     this will indicate if implicit object name for the language
-  ///     like "this" for C++, and "self" for Objective C.
-  ///
   /// \return
   ///     Returns true if this is a decl context that represents a method
   ///     in a struct, union or class.
-  bool IsClassMethod(ConstString *language_object_name_ptr = nullptr);
+  bool IsClassMethod();
+
+  /// Determines the original language of the decl context.
+  lldb::LanguageType GetLanguage();
+
+  /// Determines the name of the instance variable for the this decl context.
+  ///
+  /// For C++ the name is "this", for Objective-C the name is "self".
+  ///
+  /// \return
+  ///     Returns a string for the name of the instance variable.
+  ConstString GetInstanceVariableName(lldb::LanguageType language);
 
   /// Check if the given other decl context is contained in the lookup
   /// of this decl context (for example because the other context is a nested
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to