diff --git a/lldb/include/lldb/Symbol/CompilerDeclContext.h b/lldb/include/lldb/Symbol/CompilerDeclContext.h --- a/lldb/include/lldb/Symbol/CompilerDeclContext.h +++ b/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 diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h --- a/lldb/include/lldb/Symbol/SymbolContext.h +++ b/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 /// diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/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; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/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 GetCXXClassName(const CompilerType &type); // Type Completion diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- 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 @@ 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 TypeSystemClang::GetCXXClassName(const CompilerType &type) { if (!type) @@ -9751,32 +9769,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(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(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(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(decl_ctx)) { + return true; + } else if (llvm::isa(decl_ctx)) { + return true; + } else if (clang::FunctionDecl *fun_decl = + llvm::dyn_cast(decl_ctx)) { + if (ClangASTMetadata *metadata = GetMetadata(fun_decl)) + return metadata->HasObjectPtr(); } + return false; } @@ -9797,6 +9804,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(decl_ctx)) { + return eLanguageTypeObjC; + } else if (llvm::isa(decl_ctx)) { + return eLanguageTypeC_plus_plus; + } else if (auto *fun_decl = llvm::dyn_cast(decl_ctx)) { + if (ClangASTMetadata *metadata = GetMetadata(fun_decl)) + return metadata->GetObjectPtrLanguage(); + } + + return eLanguageTypeUnknown; +} + static bool IsClangDeclContext(const CompilerDeclContext &dc) { return dc.IsValid() && isa(dc.GetTypeSystem()); } diff --git a/lldb/source/Symbol/CompilerDeclContext.cpp b/lldb/source/Symbol/CompilerDeclContext.cpp --- a/lldb/source/Symbol/CompilerDeclContext.cpp +++ b/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; diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp --- a/lldb/source/Symbol/SymbolContext.cpp +++ b/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 { diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp --- a/lldb/source/Target/StackFrame.cpp +++ b/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 (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 --- 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 --- 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 @@ 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 --- 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 @@ @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]; }