Skip to content

Commit 4faf411

Browse files
committed
[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 (cherry picked from commit 6c599b1)
1 parent 5ff1e2f commit 4faf411

File tree

11 files changed

+140
-73
lines changed

11 files changed

+140
-73
lines changed

lldb/include/lldb/Symbol/CompilerDeclContext.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,21 @@ class CompilerDeclContext {
6161

6262
/// Checks if this decl context represents a method of a class.
6363
///
64-
/// \param[out] language_object_name_ptr
65-
/// If non NULL and \b true is returned from this function,
66-
/// this will indicate if implicit object name for the language
67-
/// like "this" for C++, and "self" for Objective C.
68-
///
6964
/// \return
7065
/// Returns true if this is a decl context that represents a method
7166
/// in a struct, union or class.
72-
bool IsClassMethod(ConstString *language_object_name_ptr = nullptr);
67+
bool IsClassMethod();
68+
69+
/// Determines the original language of the decl context.
70+
lldb::LanguageType GetLanguage();
71+
72+
/// Determines the name of the instance variable for the this decl context.
73+
///
74+
/// For C++ the name is "this", for Objective-C the name is "self".
75+
///
76+
/// \return
77+
/// Returns a string for the name of the instance variable.
78+
ConstString GetInstanceVariableName(lldb::LanguageType language);
7379

7480
/// Check if the given other decl context is contained in the lookup
7581
/// of this decl context (for example because the other context is a nested

lldb/include/lldb/Symbol/SymbolContext.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,17 +245,13 @@ class SymbolContext {
245245
/// represented by this symbol context object, nullptr otherwise.
246246
Block *GetFunctionBlock();
247247

248-
/// If this symbol context represents a function that is a method, return
249-
/// true and provide information about the method.
248+
/// Determines the name of the instance variable for the this decl context.
250249
///
251-
/// \param[out] language_object_name
252-
/// If \b true is returned, the name of the artificial variable
253-
/// for the language ("this" for C++, "self" for ObjC).
250+
/// For C++ the name is "this", for Objective-C the name is "self".
254251
///
255252
/// \return
256-
/// \b True if this symbol context represents a function that
257-
/// is a method of a class, \b false otherwise.
258-
bool GetFunctionMethodInfo(ConstString &language_object_name);
253+
/// Returns a string for the name of the instance variable.
254+
ConstString GetInstanceVariableName();
259255

260256
/// Sorts the types in TypeMap according to SymbolContext to TypeList
261257
///

lldb/include/lldb/Symbol/TypeSystem.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,13 @@ class TypeSystem : public PluginInterface,
131131
virtual ConstString
132132
DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) = 0;
133133

134-
virtual bool
135-
DeclContextIsClassMethod(void *opaque_decl_ctx,
136-
ConstString *language_object_name_ptr) = 0;
134+
virtual bool DeclContextIsClassMethod(void *opaque_decl_ctx) = 0;
137135

138136
virtual bool DeclContextIsContainedInLookup(void *opaque_decl_ctx,
139137
void *other_opaque_decl_ctx) = 0;
140138

139+
virtual lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) = 0;
140+
141141
// Tests
142142
#ifndef NDEBUG
143143
/// Verify the integrity of the type to catch CompilerTypes that mix
@@ -217,6 +217,10 @@ class TypeSystem : public PluginInterface,
217217
// an error.
218218
virtual Status IsCompatible();
219219

220+
/// The name of the variable used for explicitly accessing data scoped to the
221+
/// current instance (or type). C++ uses "this", ObjC uses "self".
222+
virtual ConstString GetInstanceVariableName(lldb::LanguageType language) = 0;
223+
220224
// Type Completion
221225

222226
virtual bool GetCompleteType(lldb::opaque_compiler_type_t type) = 0;

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "TypeSystemClang.h"
1010

11+
#include "clang/AST/DeclBase.h"
12+
#include "llvm/Support/Casting.h"
1113
#include "llvm/Support/FormatAdapters.h"
1214
#include "llvm/Support/FormatVariadic.h"
1315

@@ -3707,6 +3709,22 @@ bool TypeSystemClang::SupportsLanguage(lldb::LanguageType language) {
37073709
return TypeSystemClangSupportsLanguage(language);
37083710
}
37093711

3712+
ConstString
3713+
TypeSystemClang::GetInstanceVariableName(lldb::LanguageType language) {
3714+
switch (language) {
3715+
case LanguageType::eLanguageTypeC_plus_plus:
3716+
case LanguageType::eLanguageTypeC_plus_plus_03:
3717+
case LanguageType::eLanguageTypeC_plus_plus_11:
3718+
case LanguageType::eLanguageTypeC_plus_plus_14:
3719+
return ConstString("this");
3720+
case LanguageType::eLanguageTypeObjC:
3721+
case LanguageType::eLanguageTypeObjC_plus_plus:
3722+
return ConstString("self");
3723+
default:
3724+
return {};
3725+
}
3726+
}
3727+
37103728
Optional<std::string>
37113729
TypeSystemClang::GetCXXClassName(const CompilerType &type) {
37123730
if (!type)
@@ -9721,32 +9739,21 @@ TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) {
97219739
return ConstString();
97229740
}
97239741

9724-
bool TypeSystemClang::DeclContextIsClassMethod(
9725-
void *opaque_decl_ctx, ConstString *language_object_name_ptr) {
9726-
if (opaque_decl_ctx) {
9727-
clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
9728-
if (ObjCMethodDecl *objc_method =
9729-
llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx)) {
9730-
if (objc_method->isInstanceMethod())
9731-
if (language_object_name_ptr)
9732-
language_object_name_ptr->SetCString("self");
9733-
return true;
9734-
} else if (CXXMethodDecl *cxx_method =
9735-
llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx)) {
9736-
if (cxx_method->isInstance())
9737-
if (language_object_name_ptr)
9738-
language_object_name_ptr->SetCString("this");
9739-
return true;
9740-
} else if (clang::FunctionDecl *function_decl =
9741-
llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
9742-
ClangASTMetadata *metadata = GetMetadata(function_decl);
9743-
if (metadata && metadata->HasObjectPtr()) {
9744-
if (language_object_name_ptr)
9745-
language_object_name_ptr->SetCString(metadata->GetObjectPtrName());
9746-
return true;
9747-
}
9748-
}
9742+
bool TypeSystemClang::DeclContextIsClassMethod(void *opaque_decl_ctx) {
9743+
if (!opaque_decl_ctx)
9744+
return false;
9745+
9746+
clang::DeclContext *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
9747+
if (llvm::isa<clang::ObjCMethodDecl>(decl_ctx)) {
9748+
return true;
9749+
} else if (llvm::isa<clang::CXXMethodDecl>(decl_ctx)) {
9750+
return true;
9751+
} else if (clang::FunctionDecl *fun_decl =
9752+
llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
9753+
if (ClangASTMetadata *metadata = GetMetadata(fun_decl))
9754+
return metadata->HasObjectPtr();
97499755
}
9756+
97509757
return false;
97519758
}
97529759

@@ -9767,6 +9774,24 @@ bool TypeSystemClang::DeclContextIsContainedInLookup(
97679774
return false;
97689775
}
97699776

9777+
lldb::LanguageType
9778+
TypeSystemClang::DeclContextGetLanguage(void *opaque_decl_ctx) {
9779+
if (!opaque_decl_ctx)
9780+
return eLanguageTypeUnknown;
9781+
9782+
auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx;
9783+
if (llvm::isa<clang::ObjCMethodDecl>(decl_ctx)) {
9784+
return eLanguageTypeObjC;
9785+
} else if (llvm::isa<clang::CXXMethodDecl>(decl_ctx)) {
9786+
return eLanguageTypeC_plus_plus;
9787+
} else if (auto *fun_decl = llvm::dyn_cast<clang::FunctionDecl>(decl_ctx)) {
9788+
if (ClangASTMetadata *metadata = GetMetadata(fun_decl))
9789+
return metadata->GetObjectPtrLanguage();
9790+
}
9791+
9792+
return eLanguageTypeUnknown;
9793+
}
9794+
97709795
static bool IsClangDeclContext(const CompilerDeclContext &dc) {
97719796
return dc.IsValid() && isa<TypeSystemClang>(dc.GetTypeSystem());
97729797
}

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,12 +570,13 @@ class TypeSystemClang : public TypeSystem {
570570

571571
ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override;
572572

573-
bool DeclContextIsClassMethod(void *opaque_decl_ctx,
574-
ConstString *language_object_name_ptr) override;
573+
bool DeclContextIsClassMethod(void *opaque_decl_ctx) override;
575574

576575
bool DeclContextIsContainedInLookup(void *opaque_decl_ctx,
577576
void *other_opaque_decl_ctx) override;
578577

578+
lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) override;
579+
579580
// Clang specific clang::DeclContext functions
580581

581582
static clang::DeclContext *
@@ -703,6 +704,8 @@ class TypeSystemClang : public TypeSystem {
703704

704705
bool SupportsLanguage(lldb::LanguageType language) override;
705706

707+
ConstString GetInstanceVariableName(lldb::LanguageType language) override;
708+
706709
static llvm::Optional<std::string> GetCXXClassName(const CompilerType &type);
707710

708711
// Type Completion

lldb/source/Symbol/CompilerDeclContext.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,25 @@ ConstString CompilerDeclContext::GetScopeQualifiedName() const {
3434
return ConstString();
3535
}
3636

37-
bool CompilerDeclContext::IsClassMethod(ConstString *language_object_name_ptr) {
37+
bool CompilerDeclContext::IsClassMethod() {
3838
if (IsValid())
39-
return m_type_system->DeclContextIsClassMethod(m_opaque_decl_ctx,
40-
language_object_name_ptr);
39+
return m_type_system->DeclContextIsClassMethod(m_opaque_decl_ctx);
4140
return false;
4241
}
4342

43+
lldb::LanguageType CompilerDeclContext::GetLanguage() {
44+
if (IsValid())
45+
return m_type_system->DeclContextGetLanguage(m_opaque_decl_ctx);
46+
return {};
47+
}
48+
49+
ConstString
50+
CompilerDeclContext::GetInstanceVariableName(lldb::LanguageType language) {
51+
if (IsValid())
52+
return m_type_system->GetInstanceVariableName(language);
53+
return {};
54+
}
55+
4456
bool CompilerDeclContext::IsContainedInLookup(CompilerDeclContext other) const {
4557
if (!IsValid())
4658
return false;

lldb/source/Symbol/SymbolContext.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -539,14 +539,16 @@ Block *SymbolContext::GetFunctionBlock() {
539539
return nullptr;
540540
}
541541

542-
bool SymbolContext::GetFunctionMethodInfo(ConstString &language_object_name) {
543-
Block *function_block = GetFunctionBlock();
544-
if (function_block) {
545-
CompilerDeclContext decl_ctx = function_block->GetDeclContext();
546-
if (decl_ctx)
547-
return decl_ctx.IsClassMethod(&language_object_name);
548-
}
549-
return false;
542+
ConstString SymbolContext::GetInstanceVariableName() {
543+
if (Block *function_block = GetFunctionBlock())
544+
if (CompilerDeclContext decl_ctx = function_block->GetDeclContext()) {
545+
auto language = decl_ctx.GetLanguage();
546+
if (language == eLanguageTypeUnknown)
547+
language = GetLanguage();
548+
return decl_ctx.GetInstanceVariableName(language);
549+
}
550+
551+
return {};
550552
}
551553

552554
void SymbolContext::SortTypeList(TypeMap &type_map, TypeList &type_list) const {

lldb/source/Target/StackFrame.cpp

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -567,23 +567,20 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
567567
// Check for direct ivars access which helps us with implicit access to
568568
// ivars using "this" or "self".
569569
GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock);
570-
ConstString method_object_name;
571-
if (m_sc.GetFunctionMethodInfo(method_object_name)) {
572-
if (method_object_name) {
573-
var_sp = variable_list->FindVariable(method_object_name);
574-
if (var_sp) {
575-
separator_idx = 0;
576-
if (Type *var_type = var_sp->GetType())
577-
if (auto compiler_type = var_type->GetForwardCompilerType())
578-
if (!compiler_type.IsPointerType())
579-
var_expr_storage = ".";
580-
581-
if (var_expr_storage.empty())
582-
var_expr_storage = "->";
583-
var_expr_storage += var_expr;
584-
var_expr = var_expr_storage;
585-
synthetically_added_instance_object = true;
586-
}
570+
if (auto instance_var_name = m_sc.GetInstanceVariableName()) {
571+
var_sp = variable_list->FindVariable(instance_var_name);
572+
if (var_sp) {
573+
separator_idx = 0;
574+
if (Type *var_type = var_sp->GetType())
575+
if (auto compiler_type = var_type->GetForwardCompilerType())
576+
if (!compiler_type.IsPointerType())
577+
var_expr_storage = ".";
578+
579+
if (var_expr_storage.empty())
580+
var_expr_storage = "->";
581+
var_expr_storage += var_expr;
582+
var_expr = var_expr_storage;
583+
synthetically_added_instance_object = true;
587584
}
588585
}
589586
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
OBJC_SOURCES := main.m
2+
CFLAGS_EXTRAS := -fblocks -fobjc-arc
3+
LD_EXTRAS := -lobjc
24
include Makefile.rules

lldb/test/API/commands/frame/var/direct-ivar/objc/TestFrameVarDirectIvarObjC.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,11 @@ def test_objc_self(self):
1010
self.build()
1111
lldbutil.run_to_source_breakpoint(self, "// check self", lldb.SBFileSpec("main.m"))
1212
self.expect("frame variable _ivar", startstr="(int) _ivar = 30")
13+
14+
@skipUnlessDarwin
15+
def test_objc_self_capture_idiom(self):
16+
self.build()
17+
lldbutil.run_to_source_breakpoint(self, "// check idiomatic self", lldb.SBFileSpec("main.m"))
18+
self.expect("frame variable weakSelf", startstr="(Classic *) weakSelf = 0x")
19+
self.expect("frame variable self", startstr="(Classic *) self = 0x")
20+
self.expect("frame variable _ivar", startstr="(int) _ivar = 30")

0 commit comments

Comments
 (0)