-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb] Add SBType::FindDirectNestedType() function #68705
Conversation
@llvm/pr-subscribers-lldb Author: Vlad Serebrennikov (Endilll) ChangesThis patch adds a This is driven by my work on formatters for Clang and LLVM types. In particular, by Related Discourse thread: https://discourse.llvm.org/t/traversing-member-types-of-a-type/72452 Full diff: https://github.com/llvm/llvm-project/pull/68705.diff 9 Files Affected:
diff --git a/lldb/bindings/interface/SBTypeDocstrings.i b/lldb/bindings/interface/SBTypeDocstrings.i
index 96421a6aa20104b..b4ec67da957c7d4 100644
--- a/lldb/bindings/interface/SBTypeDocstrings.i
+++ b/lldb/bindings/interface/SBTypeDocstrings.i
@@ -720,6 +720,13 @@ SBType supports the eq/ne operator. For example,::
"
) lldb::SBType::GetTypeFlags;
+%feature("docstring",
+ "Searches for a nested type that has provided name.
+
+ Returns the type if it was found.
+ Returns invalid type if nothing was found."
+) lldb::SBType::FindNestedType;
+
%feature("docstring",
"Represents a list of :py:class:`SBType` s.
diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h
index 5962f0c50dee14f..fa02197ff8f3940 100644
--- a/lldb/include/lldb/API/SBType.h
+++ b/lldb/include/lldb/API/SBType.h
@@ -215,6 +215,8 @@ class SBType {
bool GetDescription(lldb::SBStream &description,
lldb::DescriptionLevel description_level);
+ lldb::SBType FindNestedType(const char *name);
+
lldb::SBType &operator=(const lldb::SBType &rhs);
bool operator==(lldb::SBType &rhs);
diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h
index 046501931d211a7..6da4aaba401fe14 100644
--- a/lldb/include/lldb/Symbol/Type.h
+++ b/lldb/include/lldb/Symbol/Type.h
@@ -313,6 +313,8 @@ class TypeImpl {
bool GetDescription(lldb_private::Stream &strm,
lldb::DescriptionLevel description_level);
+ CompilerType FindNestedType(ConstString name);
+
private:
bool CheckModule(lldb::ModuleSP &module_sp) const;
bool CheckExeModule(lldb::ModuleSP &module_sp) const;
diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index eb6e453e1aec0d0..b503b66eb528c68 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -135,6 +135,10 @@ class TypeSystem : public PluginInterface,
virtual lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) = 0;
+ // CompilerType functions
+
+ virtual CompilerDeclContext GetCompilerDeclContextForType(const CompilerType& type);
+
// Tests
#ifndef NDEBUG
/// Verify the integrity of the type to catch CompilerTypes that mix
diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index ee5b6447428098e..7fe1836ea5d670b 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -586,6 +586,15 @@ lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) {
return eTemplateArgumentKindNull;
}
+SBType SBType::FindNestedType(const char *name) {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (!IsValid())
+ return SBType();
+ auto ret = SBType(m_opaque_sp->FindNestedType(ConstString(name)));
+ return ret;
+}
+
SBTypeList::SBTypeList() : m_opaque_up(new TypeListImpl()) {
LLDB_INSTRUMENT_VA(this);
}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 69cff0f35ae4ab2..b4bf3d3fdb20c1e 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2636,6 +2636,10 @@ TypeSystemClang::GetDeclContextForType(const CompilerType &type) {
return GetDeclContextForType(ClangUtil::GetQualType(type));
}
+CompilerDeclContext TypeSystemClang::GetCompilerDeclContextForType(const CompilerType& type) {
+ return CreateDeclContext(GetDeclContextForType(type));
+}
+
/// Aggressively desugar the provided type, skipping past various kinds of
/// syntactic sugar and other constructs one typically wants to ignore.
/// The \p mask argument allows one to skip certain kinds of simplifications,
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 0544de3cd33befb..806ff64ef0af76b 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -219,6 +219,8 @@ class TypeSystemClang : public TypeSystem {
static clang::DeclContext *GetDeclContextForType(const CompilerType &type);
+ CompilerDeclContext GetCompilerDeclContextForType(const CompilerType &type) override;
+
uint32_t GetPointerByteSize() override;
clang::TranslationUnitDecl *GetTranslationUnitDecl() {
diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp
index 66284eb73cad038..724973b1fd9bd06 100644
--- a/lldb/source/Symbol/Type.cpp
+++ b/lldb/source/Symbol/Type.cpp
@@ -1082,6 +1082,19 @@ bool TypeImpl::GetDescription(lldb_private::Stream &strm,
return true;
}
+CompilerType TypeImpl::FindNestedType(ConstString name) {
+ auto type_system = GetTypeSystem(false);
+ auto *symbol_file = type_system->GetSymbolFile();
+ auto decl_context = type_system->GetCompilerDeclContextForType(m_static_type);
+ llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
+ TypeMap search_result;
+ symbol_file->FindTypes(name, decl_context, /*max_matches*/ 1, searched_symbol_files, search_result);
+ if (search_result.Empty()) {
+ return CompilerType();
+ }
+ return search_result.GetTypeAtIndex(0)->GetFullCompilerType();
+}
+
bool TypeMemberFunctionImpl::IsValid() {
return m_type.IsValid() && m_kind != lldb::eMemberFunctionKindUnknown;
}
diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp
index 24f20293056501f..ce24e312f4f35e0 100644
--- a/lldb/source/Symbol/TypeSystem.cpp
+++ b/lldb/source/Symbol/TypeSystem.cpp
@@ -186,6 +186,10 @@ std::optional<llvm::json::Value> TypeSystem::ReportStatistics() {
return std::nullopt;
}
+CompilerDeclContext TypeSystem::GetCompilerDeclContextForType(const CompilerType& type) {
+ return CompilerDeclContext();
+}
+
#pragma mark TypeSystemMap
TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Intended usage is going to look like the following for class PointerIntPairProvider:
def update(self):
pointer_info = self.valobj.type.template_args[4] # PointerIntPairInfo
masks = pointer_info.FindNestedType("MaskAndShiftConstants")
if masks.IsValid():
for enumerator in enum.enum_members:
if enumerator.name == "PointerBitMask":
pointer_mask = enumerator.unsigned
# extract pointer using the mask Fully qualified name of I'll submit a proper API test shortly. |
It should be noted that after calling uint32_t TypeSystemClang::GetNumMemberEnums(lldb::opaque_compiler_type_t type) {
using EnumIt = clang::DeclContext::specific_decl_iterator<clang::EnumDecl>;
if (!type)
return 0;
clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
if (GetCompleteQualType(&getASTContext(), qual_type)) {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl = record_type->getDecl();
assert(record_decl);
auto result = std::distance(EnumIt(record_decl->decls_begin()), EnumIt(record_decl->decls_end()));
return result;
}
return 0;
} It's also available here: https://github.com/Endilll/llvm-project/blob/fbad2d1fd8e9c67e4de8a196df0cd1d1788fa990/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp#L7080-L7095 |
The idea seems good. If you are looking for a type and you know it is defined inside another type, then providing a way for you to tell lldb that is useful. Is FindNestedType guaranteed to have a single return? What if I had:
Then I would expect
to return both A::B::D and A::E::D. So you might need to return a SBTypeList here? You could also add a |
Yes, because search is not recursive, i.e. doesn't search inside nested types. |
Not sure why you say "SBTarget::FindFirstType" is a replacement for the deeper search, since it will search the whole type landscape which is what your search allows us to avoid...
You could make this API more general by adding a "depth" parameter:
SBTypeList SBType::FindNestedTypes(const char *name, uint32_t depth);
Your use case would pass depth of 1, and retain the speed you intend, but allow for more general searches.
If you do that I think the API is great. If you still just want to do 1 level depth search, then I think you have to reflect that more clearly in the name. I would NOT expect FindNestedType to only search one level deep because that's the only way it would be guaranteed to only return a singular type. If you want to keep it this way, you should do something like "FindDirectlyNestedType" though that makes it more obvious that this is an oddly limited API...
Jim
… On Oct 10, 2023, at 9:58 AM, Vlad Serebrennikov ***@***.***> wrote:
Is FindNestedType guaranteed to have a single return?
Yes, because search is not recursive, i.e. doesn't search inside nested types.
I'm intentionally specifying FindNestedType this way, because I'd like it to not do too much to remain fast by design, and I'm yet to see a use case when I'd be interested in type NN, buried inside arbitrary number of intervening nested types. Even if there is such use case, SBTarget::FindFirstType could be a better fit to address it.
—
Reply to this email directly, view it on GitHub <#68705 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ADUPVW24DW7TW3NAJT7XNJDX6V5BTAVCNFSM6AAAAAA52MJQ3SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTONJVHA3TANRYGU>.
You are receiving this because your review was requested.
|
Now I wonder how my current implementation behaves with respect to depth, which is actually embarrassing. And how to implement |
0 to mean unlimited search sounds good to me. |
llvm-project/lldb/source/Symbol/CompilerDeclContext.cpp Lines 49 to 61 in d5444ab
and llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp Lines 9697 to 9712 in d5444ab
suggest that depth of the search is type-system-dependent, and that Clang type system doesn't do recursive check, save for inline namespaces, which doesn't matter for this PR. I don't mind writing an interface for recursive search and saying somewhere that depths other that 1 are not yet supported, but I consider it out of scope of this PR (and my use case) to implement recursive search. Does this sound good to you, or you'd prefer something along the lines of FindDirectNestedType ?
|
Just to make sure I understand. You're using FindTypes in a DeclContext using max_matches == 1. But FindTypes will recurse in the DeclContext, so depending on the actual search implementation, you could have a situation like:
where if we do depth first we could start recursing down B, find A::B::C which is a match, note max_matches == 1 and return. So this is really just FindFirstNestedType, I don't think you can make any claim about directness given how this is implemented. I still think the idea of allowing a type search to be limited to a given type context is useful. We usually do "FindWhatever" returning a list, and "FindFirstWhatever" returning some not described algorithm's chosen "first" match. It's a little odd to add the "First" w/o the list version, however. |
Looking at For the context, this is the first check search algorithm performs while determining a match:
|
Yes, if this API is going to claim to only find directly contained types, there needs to be an explicit guarantee that that's what the underlying API's do. The API you call should state that it is doing that, and you also need to write tests that make sure we only see direct types and not ones deeper in the hierarchy. |
It's not clear to me whether |
It might be good to ask this as a separate question on the lldb project Discourse (https://discourse.llvm.org/c/subprojects/lldb/8). That's likely to get more notice than a comment deep in a patch review. |
We use |
As long as it does (and will continue doing) what it says, Part of me thinks: "later on somebody will want to add an N levels deep search -requiring a depth parameter, and then we'll have to add another But adding a depth parameter now to future-proof the API and only supporting 1 (leaving others to fill in the rest of the functionality) also seems a bit weak. So I end up not having a strong feeling either way, and the functionality is useful. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, if @jimingham doesn't have any other comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with some small nits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! LGTM.
This patch adds a
SBType::FindDirectNestedType(name)
function which performs a non-recursive search in given class for a type with specified name. The intent is to perform a fast search in debug info, so that it can be used in formatters, and let them remain responsive.This is driven by my work on formatters for Clang and LLVM types. In particular, by
PointerIntPairInfo::MaskAndShiftConstants
, which is required to extract pointer and integer fromPointerIntPair
.Related Discourse thread: https://discourse.llvm.org/t/traversing-member-types-of-a-type/72452