[Lldb-commits] [lldb] 6c599b1 - [lldb] Let 'v' command directly access ivars of _any_ self/this
Dave Lee via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 8 11:19:53 PST 2023
Author: Dave Lee
Date: 2023-03-08T11:19:43-08:00
New Revision: 6c599b1e9b7e1b57952565468aed2de16af21082
URL: https://github.com/llvm/llvm-project/commit/6c599b1e9b7e1b57952565468aed2de16af21082
DIFF: https://github.com/llvm/llvm-project/commit/6c599b1e9b7e1b57952565468aed2de16af21082.diff
LOG: [lldb] Let 'v' command directly access ivars of _any_ self/this
The `v` (`frame variable`) command can directly access ivars/fields of `this` or `self`.
Such as `v field`, instead of `v this->field`. This change relaxes the criteria for
finding `this`/`self` variables.
There are cases where a `this`/`self` variable does exist, but up to now the `v` command
has not made use of it. The user would have to explicitly run `v this->field` or
`self->_ivar` to access ivars. This change allows such cases to also work (without
explicitly dereferencing `this`/`self`).
A very common example in Objective-C (and Swift) is weakly capturing `self`:
```
__weak Type *weakSelf = self;
void (^block)(void) = ^{
Type *self = weakSelf; // Re-establish strong reference.
// `v _ivar` should work just as well as `v self->_ivar`.
};
```
In this case, `self` exists but `v` would not have used it. With this change, the fact
that a variable named `self` exists is enough for it to be used.
Differential Revision: https://reviews.llvm.org/D145276
Added:
Modified:
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
Removed:
################################################################################
diff --git a/lldb/include/lldb/Symbol/CompilerDeclContext.h b/lldb/include/lldb/Symbol/CompilerDeclContext.h
index ca404a6641d5e..63e5f7b680e63 100644
--- a/lldb/include/lldb/Symbol/CompilerDeclContext.h
+++ b/lldb/include/lldb/Symbol/CompilerDeclContext.h
@@ -61,15 +61,21 @@ class CompilerDeclContext {
/// 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
diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h
index bb9e031daaaa4..73fa25514aff3 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -245,17 +245,13 @@ class SymbolContext {
/// 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
///
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index 7681a700766a2..0777d4d5ad6f3 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -127,13 +127,13 @@ class TypeSystem : public PluginInterface,
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 @@ class TypeSystem : public PluginInterface,
// 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;
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 81feea9e4a5dc..61d7dff2e00b8 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/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 @@ bool TypeSystemClang::SupportsLanguage(lldb::LanguageType language) {
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)
@@ -9751,32 +9769,21 @@ TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) {
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;
}
@@ -9797,6 +9804,24 @@ bool TypeSystemClang::DeclContextIsContainedInLookup(
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());
}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 99021f9b76bda..baddf6253beb4 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -579,12 +579,13 @@ class TypeSystemClang : public TypeSystem {
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 @@ class TypeSystemClang : public TypeSystem {
bool SupportsLanguage(lldb::LanguageType language) override;
+ ConstString GetInstanceVariableName(lldb::LanguageType language) override;
+
static std::optional<std::string> GetCXXClassName(const CompilerType &type);
// Type Completion
diff --git a/lldb/source/Symbol/CompilerDeclContext.cpp b/lldb/source/Symbol/CompilerDeclContext.cpp
index 5b3049f74bbc8..36b9131055f83 100644
--- a/lldb/source/Symbol/CompilerDeclContext.cpp
+++ b/lldb/source/Symbol/CompilerDeclContext.cpp
@@ -34,13 +34,25 @@ ConstString CompilerDeclContext::GetScopeQualifiedName() const {
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;
diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp
index 8453c1f116fef..5d4fb1cec6969 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -539,14 +539,16 @@ Block *SymbolContext::GetFunctionBlock() {
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 {
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index fa74b5d0ac2c6..f828539057cbf 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -567,23 +567,20 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
// 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 (var_expr_storage.empty())
- var_expr_storage = "->";
- var_expr_storage += var_expr;
- var_expr = var_expr_storage;
- synthetically_added_instance_object = true;
- }
+ 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;
}
}
}
diff --git a/lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile b/lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile
index d0aadc1af9e58..c07887aa2f1df 100644
--- a/lldb/test/API/commands/frame/var/direct-ivar/objc/Makefile
+++ b/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
diff --git a/lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py b/lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
index 395e014b2d88f..c93dc9ea1d9a0 100644
--- a/lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
+++ b/lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py
@@ -10,3 +10,11 @@ def test_objc_self(self):
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")
diff --git a/lldb/test/API/commands/frame/var/direct-ivar/objc/main.m b/lldb/test/API/commands/frame/var/direct-ivar/objc/main.m
index 3d5ef38dd3187..156622ffb1e63 100644
--- a/lldb/test/API/commands/frame/var/direct-ivar/objc/main.m
+++ b/lldb/test/API/commands/frame/var/direct-ivar/objc/main.m
@@ -7,13 +7,25 @@ @interface Classic : NSObject {
@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];
}
More information about the lldb-commits
mailing list