Skip to content

[lldb] Implement TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName #2260

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

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
95dd368
thread exe_ctx through GetIndexOfChild(Member)?WithName
kastiglione Dec 17, 2020
0a86741
call newly stubbed SwiftLanguageRuntime::GetIndexOfChildMemberWithName
kastiglione Dec 17, 2020
4bd5d15
use StringRef and MutableArrayRef in new API
kastiglione Dec 17, 2020
7b8951c
revert MutableArrayRef back to vector
kastiglione Dec 17, 2020
d0a8d14
implement most of GetIndexOfChildMemberWithName
kastiglione Dec 18, 2020
0d5d9e2
in GetChildCompilerTypeAtIndex, switch fallback() to impl()
kastiglione Dec 18, 2020
ba443ff
rework GetIndexOfChildMemberWithName validation
kastiglione Dec 18, 2020
93a4ce8
first changes to tests now that these private members are visible
kastiglione Dec 18, 2020
b85f9cd
take base class into account when calculating member index
kastiglione Dec 18, 2020
fc3c654
use <3 instead of <=2 - for consistency
kastiglione Dec 18, 2020
1d92d40
dereference weak types
kastiglione Dec 18, 2020
d89aacb
traverse class hierarchy
kastiglione Dec 18, 2020
74d407a
fix superclass iteration
kastiglione Dec 18, 2020
ff5203d
return 0 not None for ThickFunction
kastiglione Dec 18, 2020
49a045c
handle ExistentialMetatype in SwiftLanguageRuntimeImpl
kastiglione Dec 18, 2020
094fdb3
update TestLibraryIndirect.py
kastiglione Dec 19, 2020
922d587
comment: LLDB can find it through type metadata
kastiglione Dec 19, 2020
5d0f70d
use `T v(...)` style initialization
kastiglione Dec 19, 2020
466cba7
update No.swiftmodule.swift
kastiglione Dec 19, 2020
dd9ee01
reenable TestSwiftFoundationTypeNotification.py
kastiglione Dec 19, 2020
ecc71dd
add superclass to child_indexes
kastiglione Dec 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lldb/include/lldb/Symbol/CompilerType.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class CompilerType {

/// Lookup a child given a name. This function will match base class names and
/// member member names in "clang_type" only, not descendants.
uint32_t GetIndexOfChildWithName(const char *name,
uint32_t GetIndexOfChildWithName(const char *name, ExecutionContext *exe_ctx,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should eventually upstream this change, but I don't see an issue with doing so. @jimingham previously pointed out that requiring a ValueObject in CompilerType is problematic, but there is prior art for requiring an optional ExecutionContext in calls like GetBitSize(). @jimingham do you agree with that characterization?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for what it's worth, the functions I've seen need the process, so passing a process instead of ExecutionContext makes the dependency clearer, at the cost of being less flexible if in the future something else from the context is needed instead of or in addition to the process.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an API for all TypeSystems, maybe keeping it more general is actually desirable? It also looks like most CompilerType methods (https://lldb.llvm.org/cpp_reference/classlldb__private_1_1CompilerType.html) take an ExecutionContextScope. Maybe we should also do that here too, for symmetry?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use cases and distinction between ExecutionContext and ExecutionContextScope is not clear to me at all. I read their docs and looked at their APIs. The primary reason I went with ExecutionContext here is because from ValueObject it's more direct/convenient.

Within ValueObject, both of these patterns exist:

ExecutionContext exe_ctx(GetExecutionContextRef());
ExecutionContext exe_ctx(GetExecutionContextRef());
someFunction(exe_ctx.GetBestExecutionContextScope());

What's unclear to me, is why bring ExecutionContextScope into the equation? From its documentation, ExecutionContext says:

These objects are designed to be used for short term execution context object storage while a function might be trying to evaluate something that requires a thread or frame.

Which does describe the needs of SwiftLanguageRuntime.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should eventually upstream this change, but I don't see an issue with doing so. @jimingham previously pointed out that requiring a ValueObject in CompilerType is problematic, but there is prior art for requiring an optional ExecutionContext in calls like GetBitSize(). @jimingham do you agree with that characterization?

That's right. Since you really only want the process, or maybe a frame if you are trying to bind some generic, a ValueObject is way more than you need. But that you might need a process to determine some aspects of the type system, it makes sense to have API's into the type system that provide an ExecutionContext in some form.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use cases and distinction between ExecutionContext and ExecutionContextScope is not clear to me at all. I read their docs and looked at their APIs.

Before I guess an answer — @jimingham ^ ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, the ExecutionContextScope is there because it is really handy to be able to use one of the objects in the Execution Context hierarchy to stand in for a scope specifier regardless of where you are in the hierarchy. I'm not sure for local passing of contexts there's a hard and fast rule on which to use, so far as I can tell it's more a matter of convenience. If you know you will mostly always have a process/thread/frame object on hand when calling the API, then ExecutionContextScope is way more convenient as you can bypass the conversion to ExecutionContext.

But you might also want to check with Greg in case I'm misremembering something. These were his designs originally.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make the minimal API change to just add the context pointer here and then separately refurbish the API on llvm.org where we get rid of the char *, etc...

bool omit_empty_base_classes) const;

/// Lookup a child member given a name. This function will match member names
Expand All @@ -334,7 +334,8 @@ class CompilerType {
/// vector<vector<uint32_t>>
/// so we catch all names that match a given child name, not just the first.
size_t
GetIndexOfChildMemberWithName(const char *name, bool omit_empty_base_classes,
GetIndexOfChildMemberWithName(const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) const;

size_t GetNumTemplateArguments() const;
Expand Down
4 changes: 3 additions & 1 deletion lldb/include/lldb/Symbol/TypeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ class TypeSystem : public PluginInterface {
// member member names in "clang_type" only, not descendants.
virtual uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
const char *name,
ExecutionContext *exe_ctx,
bool omit_empty_base_classes) = 0;

// Lookup a child member given a name. This function will match member names
Expand All @@ -365,7 +366,8 @@ class TypeSystem : public PluginInterface {
// so we catch all names that match a given child name, not just the first.
virtual size_t
GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
const char *name, bool omit_empty_base_classes,
const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) = 0;

virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type);
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/SwiftLanguageRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ class SwiftLanguageRuntime : public LanguageRuntime {
llvm::Optional<unsigned> GetNumChildren(CompilerType type,
ValueObject *valobj);

llvm::Optional<size_t> GetIndexOfChildMemberWithName(
CompilerType type, llvm::StringRef name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good — but it would be better to use an llvm::StringRef instead of a const char* for name.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, a MutableArrayRef http://llvm.org/doxygen/classllvm_1_1MutableArrayRef.html is preferred over a std::vector&. Then call sites can also use SmallVectors if they wish to do so.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks will do! TIL about MutableArrayRef

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems MutableArrayRef won't work here, I don't see any way to modify an underlying vector, in particular to append to it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, you're right! We could go to a SmallVectorImpl<uint32_t> but the returns are marginal.

Side note: Having now read the documentation for child_indexes (https://lldb.llvm.org/cpp_reference/classlldb__private_1_1CompilerType.html#abbeabd29258512dc7869c3f01afff93d) this method's entire API is weird.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha very weird

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For posteriority: The point of the child_indexes array is to support returning more than one match. I have no idea in which language this would even be possible. To top that off, the return value is that of child_indexes[0] or INT_MAX, and the comment has a TODO mark in it. We might want to check if this is even wired up in any language backend and otherwise potentially even remove it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good to me.

In the case of multiple children with the same name, a class can have a property of the same name as a property in its base class if the base class property is private.

In my quick check of c++, it allows duplicate members names regardless of access control.

Copy link

@jimingham jimingham Dec 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It really depends on what we decide to mean by "ChildMember". If it means any member of the current object, then in C++ you can have two with the same name since they can come from different base classes. If it only means "any member contributed by the most specific class of the object, and you have to get to the others by recursing through the base class by hand", then I can't think of a way you could have two members with the same name.

I think the first meaning is more useful, but I'm not 100% set on that.

/// Ask Remote Mirrors about a child of a composite type.
CompilerType GetChildCompilerTypeAtIndex(
CompilerType type, size_t idx, bool transparent_pointers,
Expand Down
6 changes: 4 additions & 2 deletions lldb/source/Core/ValueObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,8 @@ lldb::ValueObjectSP ValueObject::GetChildAtNamePath(

size_t ValueObject::GetIndexOfChildWithName(ConstString name) {
bool omit_empty_base_classes = true;
return GetCompilerType().GetIndexOfChildWithName(name.GetCString(),
ExecutionContext exe_ctx(GetExecutionContextRef());
return GetCompilerType().GetIndexOfChildWithName(name.GetCString(), &exe_ctx,
omit_empty_base_classes);
}

Expand All @@ -614,9 +615,10 @@ ValueObjectSP ValueObject::GetChildMemberWithName(ConstString name,
if (!GetCompilerType().IsValid())
return ValueObjectSP();

ExecutionContext exe_ctx(GetExecutionContextRef());
const size_t num_child_indexes =
GetCompilerType().GetIndexOfChildMemberWithName(
name.GetCString(), omit_empty_base_classes, child_indexes);
name.GetCString(), &exe_ctx, omit_empty_base_classes, child_indexes);
if (num_child_indexes == 0)
return nullptr;

Expand Down
4 changes: 2 additions & 2 deletions lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
return UINT32_MAX;

const bool omit_empty_base_classes = false;
return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(),
omit_empty_base_classes);
return m_block_struct_type.GetIndexOfChildWithName(
name.AsCString(), nullptr, omit_empty_base_classes);
}

private:
Expand Down
26 changes: 13 additions & 13 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6504,7 +6504,8 @@ static uint32_t GetIndexForRecordChild(const clang::RecordDecl *record_decl,

size_t TypeSystemClang::GetIndexOfChildMemberWithName(
lldb::opaque_compiler_type_t type, const char *name,
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
ExecutionContext *exe_ctx, bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) {
if (type && name && name[0]) {
clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
Expand Down Expand Up @@ -6532,7 +6533,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
CompilerType field_type = GetType(field->getType());
child_indexes.push_back(child_idx);
if (field_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes))
name, exe_ctx, omit_empty_base_classes, child_indexes))
return child_indexes.size();
child_indexes.pop_back();

Expand Down Expand Up @@ -6641,7 +6642,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
GetType(getASTContext().getObjCInterfaceType(
superclass_interface_decl));
if (superclass_clang_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes)) {
name, exe_ctx, omit_empty_base_classes, child_indexes)) {
// We did find an ivar in a superclass so just return the
// results!
return child_indexes.size();
Expand All @@ -6661,7 +6662,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
->getPointeeType());
return objc_object_clang_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes);
name, exe_ctx, omit_empty_base_classes, child_indexes);
} break;

case clang::Type::ConstantArray: {
Expand Down Expand Up @@ -6713,7 +6714,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(

if (pointee_clang_type.IsAggregateType()) {
return pointee_clang_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes);
name, exe_ctx, omit_empty_base_classes, child_indexes);
}
} break;

Expand All @@ -6722,7 +6723,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(

if (pointee_clang_type.IsAggregateType()) {
return pointee_clang_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes);
name, exe_ctx, omit_empty_base_classes, child_indexes);
}
} break;

Expand All @@ -6737,10 +6738,9 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
// doesn't descend into the children, but only looks one level deep and name
// matches can include base class names.

uint32_t
TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
const char *name,
bool omit_empty_base_classes) {
uint32_t TypeSystemClang::GetIndexOfChildWithName(
lldb::opaque_compiler_type_t type, const char *name,
ExecutionContext *exe_ctx, bool omit_empty_base_classes) {
if (type && name && name[0]) {
clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type));

Expand Down Expand Up @@ -6842,7 +6842,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
llvm::cast<clang::ObjCObjectPointerType>(qual_type.getTypePtr())
->getPointeeType());
return pointee_clang_type.GetIndexOfChildWithName(
name, omit_empty_base_classes);
name, exe_ctx, omit_empty_base_classes);
} break;

case clang::Type::ConstantArray: {
Expand Down Expand Up @@ -6892,7 +6892,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
CompilerType pointee_type = GetType(reference_type->getPointeeType());

if (pointee_type.IsAggregateType()) {
return pointee_type.GetIndexOfChildWithName(name,
return pointee_type.GetIndexOfChildWithName(name, exe_ctx,
omit_empty_base_classes);
}
} break;
Expand All @@ -6903,7 +6903,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
CompilerType pointee_type = GetType(pointer_type->getPointeeType());

if (pointee_type.IsAggregateType()) {
return pointee_type.GetIndexOfChildWithName(name,
return pointee_type.GetIndexOfChildWithName(name, exe_ctx,
omit_empty_base_classes);
} else {
// if (parent_name)
Expand Down
5 changes: 3 additions & 2 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ class TypeSystemClang : public TypeSystem {
// Lookup a child given a name. This function will match base class names and
// member member names in "clang_type" only, not descendants.
uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
const char *name,
const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes) override;

// Lookup a child member given a name. This function will match member names
Expand All @@ -832,7 +832,8 @@ class TypeSystemClang : public TypeSystem {
// so we catch all names that match a given child name, not just the first.
size_t
GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
const char *name, bool omit_empty_base_classes,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we upstream the change to add the exe_ctx, we can also modernize the signature to use StringRef and ArrayRef. And perhaps even return an Optional<>!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) override;

size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
Expand Down
10 changes: 5 additions & 5 deletions lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7259,8 +7259,8 @@ CompilerType SwiftASTContext::GetChildCompilerTypeAtIndex(
// second index 1 is the child index for "m_b" within class A.

size_t SwiftASTContext::GetIndexOfChildMemberWithName(
opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) {
opaque_compiler_type_t type, const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
VALID_OR_RETURN(0);

if (type && name && name[0]) {
Expand All @@ -7282,7 +7282,7 @@ size_t SwiftASTContext::GetIndexOfChildMemberWithName(
case swift::TypeKind::UnownedStorage:
case swift::TypeKind::WeakStorage:
return ToCompilerType(swift_can_type->getReferenceStorageReferent())
.GetIndexOfChildMemberWithName(name, omit_empty_base_classes,
.GetIndexOfChildMemberWithName(name, exe_ctx, omit_empty_base_classes,
child_indexes);
case swift::TypeKind::GenericTypeParam:
case swift::TypeKind::DependentMember:
Expand Down Expand Up @@ -7363,7 +7363,7 @@ size_t SwiftASTContext::GetIndexOfChildMemberWithName(
CompilerType superclass_type =
ToCompilerType(superclass_swift_type.getPointer());
if (superclass_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes))
name, exe_ctx, omit_empty_base_classes, child_indexes))
return child_indexes.size();

// We didn't find a stored property matching "name" in our
Expand Down Expand Up @@ -7409,7 +7409,7 @@ size_t SwiftASTContext::GetIndexOfChildMemberWithName(

if (pointee_clang_type.IsAggregateType()) {
return pointee_clang_type.GetIndexOfChildMemberWithName(
name, omit_empty_base_classes, child_indexes);
name, exe_ctx, omit_empty_base_classes, child_indexes);
}
} break;
case swift::TypeKind::UnboundGeneric:
Expand Down
3 changes: 2 additions & 1 deletion lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,8 @@ class SwiftASTContext : public TypeSystemSwift {
// name, not just the first.
size_t
GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
const char *name, bool omit_empty_base_classes,
const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) override;

size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
Expand Down
9 changes: 4 additions & 5 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,11 @@ bool TypeSystemSwift::ShouldTreatScalarValueAsAddress(
.AnySet(eTypeInstanceIsPointer | eTypeIsReference);
}

uint32_t
TypeSystemSwift::GetIndexOfChildWithName(opaque_compiler_type_t type,
const char *name,
bool omit_empty_base_classes) {
uint32_t TypeSystemSwift::GetIndexOfChildWithName(
opaque_compiler_type_t type, const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes) {
std::vector<uint32_t> child_indexes;
size_t num_child_indexes = GetIndexOfChildMemberWithName(
type, name, omit_empty_base_classes, child_indexes);
type, name, exe_ctx, omit_empty_base_classes, child_indexes);
return num_child_indexes == 1 ? child_indexes.front() : UINT32_MAX;
}
2 changes: 1 addition & 1 deletion lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ class TypeSystemSwift : public TypeSystem {
/// Lookup a child given a name. This function will match base class names
/// and member names in \p type only, not descendants.
uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
const char *name,
const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes) override;

/// \}
Expand Down
60 changes: 57 additions & 3 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
#include "clang/APINotes/APINotesManager.h"
#include "clang/APINotes/APINotesReader.h"

#include <algorithm>
#include <sstream>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can avoid this...


using namespace lldb;
using namespace lldb_private;

Expand Down Expand Up @@ -1538,6 +1541,24 @@ bool Equivalent(llvm::Optional<T> l, T r) {
return Equivalent(l, llvm::Optional<T>(r));
}

template <typename T>
bool Equivalent(const std::vector<T> &l, const std::vector<T> &r) {
if (std::equal(l.begin(), l.end(), r.begin(), r.end()))
return true;

auto join = [](const std::vector<T> &v) -> std::string {
if (v.empty())
return {};
std::ostringstream buf;
buf << v[0];
for (size_t i = 1; i < v.size(); ++i)
buf << ", " << v[i];
return buf.str();
};
llvm::dbgs() << join(l) << " != " << join(r) << "\n";
return false;
}

} // namespace
#endif

Expand Down Expand Up @@ -2365,11 +2386,44 @@ CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex(
}

size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName(
opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) {
opaque_compiler_type_t type, const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) {
if (auto *exe_scope = exe_ctx->GetBestExecutionContextScope())
if (auto *runtime =
SwiftLanguageRuntime::Get(exe_scope->CalculateProcess()))
if (auto index_size = runtime->GetIndexOfChildMemberWithName(
GetCanonicalType(type), name, exe_ctx, omit_empty_base_classes,
child_indexes)) {
#ifndef NDEBUG
// This block is a custom VALIDATE_AND_RETURN implementation to support
// checking the return value, plus the by-ref `child_indexes`.
if (!m_swift_ast_context)
return *index_size;
auto v_type = ReconstructType(type);
std::vector<uint32_t> v_child_indexes;
auto v_index_size = m_swift_ast_context->GetIndexOfChildMemberWithName(
v_type, name, exe_ctx, omit_empty_base_classes, v_child_indexes);
bool equivalent =
!v_type || (Equivalent(*index_size, v_index_size) &&
Equivalent(child_indexes, v_child_indexes));
if (!equivalent)
llvm::dbgs() << "failing type was " << (const char *)type << "\n";
assert(equivalent &&
"TypeSystemSwiftTypeRef diverges from SwiftASTContext");
#endif
return *index_size;
}

LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES),
"Using SwiftASTContext::GetIndexOfChildMemberWithName fallback for "
"type %s",
AsMangledName(type));

return m_swift_ast_context->GetIndexOfChildMemberWithName(
ReconstructType(type), name, omit_empty_base_classes, child_indexes);
ReconstructType(type), name, exe_ctx, omit_empty_base_classes,
child_indexes);
}

size_t
TypeSystemSwiftTypeRef::GetNumTemplateArguments(opaque_compiler_type_t type) {
return m_swift_ast_context->GetNumTemplateArguments(ReconstructType(type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
ValueObject *valobj, uint64_t &language_flags) override;
size_t
GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
const char *name, bool omit_empty_base_classes,
const char *name, ExecutionContext *exe_ctx,
bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) override;
size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override;
CompilerType GetTypeForFormatters(lldb::opaque_compiler_type_t type) override;
Expand Down
7 changes: 4 additions & 3 deletions lldb/source/Symbol/CompilerType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,11 +654,11 @@ CompilerType CompilerType::GetChildCompilerTypeAtIndex(
// index 1 is the child index for "m_b" within class A

size_t CompilerType::GetIndexOfChildMemberWithName(
const char *name, bool omit_empty_base_classes,
const char *name, ExecutionContext *exe_ctx, bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) const {
if (IsValid() && name && name[0]) {
return m_type_system->GetIndexOfChildMemberWithName(
m_type, name, omit_empty_base_classes, child_indexes);
m_type, name, exe_ctx, omit_empty_base_classes, child_indexes);
}
return 0;
}
Expand Down Expand Up @@ -714,9 +714,10 @@ bool CompilerType::IsMeaninglessWithoutDynamicResolution() const {

uint32_t
CompilerType::GetIndexOfChildWithName(const char *name,
ExecutionContext *exe_ctx,
bool omit_empty_base_classes) const {
if (IsValid() && name && name[0]) {
return m_type_system->GetIndexOfChildWithName(m_type, name,
return m_type_system->GetIndexOfChildWithName(m_type, name, exe_ctx,
omit_empty_base_classes);
}
return UINT32_MAX;
Expand Down
Loading