Skip to content

[lldb] Eliminate SwiftASTContext from enum handling #9857

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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
81 changes: 23 additions & 58 deletions lldb/source/Plugins/Language/Swift/SwiftOptionSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "SwiftOptionSet.h"

#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "Plugins/TypeSystem/Swift/SwiftASTContext.h"
#include "Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
Expand Down Expand Up @@ -70,7 +70,7 @@ bool lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
SwiftOptionSetSummaryProvider(CompilerType clang_type)
: TypeSummaryImpl(TypeSummaryImpl::Kind::eInternal,
TypeSummaryImpl::Flags()),
TypeSummaryImpl::Flags().SetDontShowValue(true)),
m_type(clang_type), m_cases() {}

void lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
Expand All @@ -90,29 +90,8 @@ void lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
// information.
auto ts = m_type.GetTypeSystem();
TypeSystemSwift *tss = nullptr;
std::shared_ptr<SwiftASTContext> swift_ast_ctx;
if (auto trts =
ts.dyn_cast_or_null<TypeSystemSwiftTypeRef>()) {
if (auto trts = ts.dyn_cast_or_null<TypeSystemSwiftTypeRef>())
tss = trts.get();
CompilerType ast_type = trts->ReconstructType(m_type, exe_ctx);
swift_ast_ctx =
ast_type.GetTypeSystem().dyn_cast_or_null<SwiftASTContext>();
if (swift_ast_ctx) {
auto ast_decl_ts = GetAsEnumDecl(ast_type);
if (ast_decl_ts.first) {
tss = swift_ast_ctx.get();
enum_decl = ast_decl_ts.first;
m_type = ast_type;
} else {
LLDB_LOG(GetLog(LLDBLog::DataFormatters),
"Cannot get Clang type for {0}",
m_type.GetMangledTypeName());
}
} else {
LLDB_LOG(GetLog(LLDBLog::DataFormatters), "Cannot reconstruct {0}",
m_type.GetMangledTypeName());
}
}
if (!tss) {
LLDB_LOG(GetLog(LLDBLog::DataFormatters), "No typesystem");
return;
Expand Down Expand Up @@ -149,43 +128,35 @@ std::string lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
return sstr.GetString().str();
}

static bool ReadValueIfAny(ValueObject &valobj, llvm::APInt &value) {
ValueObjectSP most_qualified_sp(valobj.GetQualifiedRepresentationIfAvailable(
lldb::eDynamicDontRunTarget, true));

bool success;
value = llvm::APInt(64, most_qualified_sp->GetValueAsUnsigned(0, &success));
return success;
}

static ValueObjectSP GetRawValue(ValueObject *valobj) {
if (!valobj)
return nullptr;

static ConstString g_rawValue("rawValue");

auto rawValue_sp = valobj->GetChildMemberWithName(g_rawValue, true);

return rawValue_sp;
}

bool lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
FormatObject(ValueObject *valobj, std::string &dest,
const TypeSummaryOptions &options) {
auto rawValue_sp = GetRawValue(valobj);
if (!rawValue_sp)
return false;
StreamString ss;
DataExtractor data;
Status error;

llvm::APInt value;
if (!ReadValueIfAny(*rawValue_sp, value))
if (!valobj)
return false;
valobj->GetData(data, error);
if (error.Fail())
return false;

{
ExecutionContext exe_ctx = valobj->GetExecutionContextRef().Lock(false);
ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
StreamString case_s;
if (valobj->GetCompilerType().DumpTypeValue(
&case_s, lldb::eFormatEnum, data, 0, data.GetByteSize(), 0, 0,
exe_ctx.GetBestExecutionContextScope(), false)) {
ss << '.' << case_s.GetData();
dest.assign(ss.GetData());
return true;
}
FillCasesIfNeeded(&exe_ctx);
}

StreamString ss;
offset_t data_offset = 0;
int64_t value = data.GetMaxS64(&data_offset, data.GetByteSize());

bool first_match = true;
bool any_match = false;

Expand Down Expand Up @@ -246,11 +217,5 @@ bool lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::

bool lldb_private::formatters::swift::SwiftOptionSetSummaryProvider::
DoesPrintChildren(ValueObject *valobj) const {
auto rawValue_sp = GetRawValue(valobj);
if (!rawValue_sp)
return false;

llvm::APInt value;
// only show children if you couldn't read the value of rawValue
return (false == ReadValueIfAny(*rawValue_sp, value));
return false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ llvm::Expected<std::string> SwiftLanguageRuntime::GetEnumCaseName(
return eti->getCases()[case_index].Name;

// TODO: uncomment this after fixing projection for every type: rdar://138424904
// LogUnimplementedTypeKind(__FUNCTION__, type);
LogUnimplementedTypeKind(__FUNCTION__, type);
return llvm::createStringError("unimplemented enum kind");
}

Expand Down
12 changes: 3 additions & 9 deletions lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8469,15 +8469,9 @@ bool SwiftASTContext::DumpTypeValue(
SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type);
if (cached_enum_info) {
auto enum_elem_info = cached_enum_info->GetElementFromData(data, true);
if (enum_elem_info)
s.Printf("%s", enum_elem_info->name.GetCString());
else {
lldb::offset_t ptr = 0;
if (data.GetByteSize())
s.Printf("<invalid> (0x%" PRIx8 ")", data.GetU8(&ptr));
else
s.Printf("<empty>");
}
if (!enum_elem_info)
return false;
s.Printf("%s", enum_elem_info->name.GetCString());
return true;
} else
s.Printf("<unknown type>");
Expand Down
95 changes: 65 additions & 30 deletions lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ class ClangNameImporter {
return imported_name.getBaseName().userFacingName().str();
}

template <typename IntTy>
llvm::StringRef ProjectEnumCase(const clang::EnumDecl *decl, IntTy val) {
for (const auto *enumerator : decl->enumerators()) {
llvm::APSInt case_val = enumerator->getInitVal();
if ((case_val.isSigned() &&
llvm::APSInt::isSameValue(case_val, llvm::APSInt::get(val))) ||
(case_val.isUnsigned() &&
llvm::APSInt::isSameValue(case_val, llvm::APSInt::getUnsigned(val))))
return m_clang_importer->getEnumConstantName(enumerator).str();
}
return {};
}

private:
swift::CompilerInvocation m_compiler_invocation;
swift::SourceManager m_source_manager;
Expand Down Expand Up @@ -2638,7 +2651,8 @@ constexpr ExecutionContextScope *g_no_exe_ctx = nullptr;
return result; \
} while (0)

#define VALIDATE_AND_RETURN(IMPL, REFERENCE, TYPE, EXE_CTX, ARGS) \
#define VALIDATE_AND_RETURN_CUSTOM(IMPL, REFERENCE, TYPE, COMPARISON, EXE_CTX, \
ARGS) \
do { \
auto result = IMPL(); \
if (!ModuleList::GetGlobalModuleListProperties() \
Expand All @@ -2658,7 +2672,7 @@ constexpr ExecutionContextScope *g_no_exe_ctx = nullptr;
return result; \
bool equivalent = \
!ReconstructType(TYPE) /* missing .swiftmodule */ || \
(Equivalent( \
(COMPARISON( \
result, \
GetSwiftASTContext(GetSymbolContext(&_exe_ctx))->REFERENCE ARGS)); \
if (!equivalent) \
Expand All @@ -2668,6 +2682,9 @@ constexpr ExecutionContextScope *g_no_exe_ctx = nullptr;
return result; \
} while (0)

#define VALIDATE_AND_RETURN(IMPL, REFERENCE, TYPE, EXE_CTX, ARGS) \
VALIDATE_AND_RETURN_CUSTOM(IMPL, REFERENCE, TYPE, Equivalent, EXE_CTX, ARGS)

#define VALIDATE_AND_RETURN_EXPECTED(IMPL, REFERENCE, TYPE, EXE_CTX, ARGS) \
do { \
auto result = IMPL(); \
Expand Down Expand Up @@ -2707,7 +2724,10 @@ constexpr ExecutionContextScope *g_no_exe_ctx = nullptr;
#else
#define VALIDATE_AND_RETURN_STATIC(IMPL, REFERENCE) \
return IMPL()
#define VALIDATE_AND_RETURN(IMPL, REFERENCE, TYPE, EXE_CTX, ARGS) return IMPL();
#define VALIDATE_AND_RETURN(IMPL, REFERENCE, TYPE, COMPARISON, EXE_CTX, ARGS) \
return IMPL();
#define VALIDATE_AND_RETURN_CUSTOM(IMPL, REFERENCE, TYPE, EXE_CTX, ARGS) \
return IMPL();
#define VALIDATE_AND_RETURN_EXPECTED(IMPL, REFERENCE, TYPE, EXE_CTX, ARGS) \
return IMPL();
#endif
Expand Down Expand Up @@ -4731,18 +4751,41 @@ bool TypeSystemSwiftTypeRef::DumpTypeValue(
// In some instances, a swift `structure` wraps an objc enum. The enum
// case needs to be handled, but structs are no-ops.
auto resolved = ResolveTypeAlias(dem, node, flavor, true);
auto clang_type = std::get<CompilerType>(resolved);
if (!clang_type)
auto resolved_type = std::get<CompilerType>(resolved);
if (!resolved_type)
return false;

bool is_signed;
if (!clang_type.IsEnumerationType(is_signed))
if (!resolved_type.IsEnumerationType(is_signed))
// The type is a clang struct, not an enum.
return false;

// The type is an enum imported from clang. Try Swift type metadata first,
// and failing that fallback to the AST.
LLVM_FALLTHROUGH;
if (!resolved_type.GetTypeSystem().isa_and_nonnull<TypeSystemClang>())
return false;

// The type is an enum imported from clang.
auto qual_type = ClangUtil::GetQualType(resolved_type);
auto *enum_type =
llvm::dyn_cast_or_null<clang::EnumType>(qual_type.getTypePtrOrNull());
if (!enum_type)
return false;
auto *importer = GetNameImporter();
if (!importer)
return false;
if (!data_byte_size)
return false;
StringRef case_name;
if (is_signed) {
int64_t val = data.GetMaxS64(&data_offset, data_byte_size);
case_name = importer->ProjectEnumCase(enum_type->getDecl(), val);
} else {
uint64_t val = data.GetMaxU64(&data_offset, data_byte_size);
case_name = importer->ProjectEnumCase(enum_type->getDecl(), val);
}
if (case_name.empty())
return false;
s << case_name;
return true;
}
case Node::Kind::Enum:
case Node::Kind::BoundGenericEnum: {
Expand All @@ -4762,18 +4805,6 @@ bool TypeSystemSwiftTypeRef::DumpTypeValue(
error = toString(case_name.takeError());
}

// No result available from the runtime, fallback to the AST. This occurs
// for some Clang imported enums.
if (auto swift_ast_context =
GetSwiftASTContext(GetSymbolContext(exe_scope))) {
ExecutionContext exe_ctx;
exe_scope->CalculateExecutionContext(exe_ctx);
if (swift_ast_context->DumpTypeValue(
ReconstructType(type, &exe_ctx), s, format, data, data_offset,
data_byte_size, bitfield_bit_size, bitfield_bit_offset,
exe_scope, is_base_class))
return true;
}
s << error;
return false;
}
Expand Down Expand Up @@ -4825,17 +4856,21 @@ bool TypeSystemSwiftTypeRef::DumpTypeValue(
ConstString(((StreamString *)&s)->GetString())) &&
"TypeSystemSwiftTypeRef diverges from SwiftASTContext");
});

// SwiftASTContext fails here, details explained in RemoteASTImport.test
if (StringRef(AsMangledName(type)) == "$s15RemoteASTImport14FromMainModuleCD")
return impl();

#endif

VALIDATE_AND_RETURN(impl, DumpTypeValue, type, exe_scope,
(ReconstructType(type, exe_scope), ast_s, format, data,
data_offset, data_byte_size, bitfield_bit_size,
bitfield_bit_offset, exe_scope, is_base_class));
auto better_or_equal = [](bool a, bool b) -> bool {
if (a || a == b)
return true;

llvm::dbgs() << "TypeSystemSwiftTypeRef: " << a << " SwiftASTContext: " << b
<< "\n";
return false;
};
VALIDATE_AND_RETURN_CUSTOM(
impl, DumpTypeValue, type, better_or_equal, exe_scope,
(ReconstructType(type, exe_scope), ast_s, format, data, data_offset,
data_byte_size, bitfield_bit_size, bitfield_bit_offset, exe_scope,
is_base_class));
}

bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,4 @@
from lldbsuite.test.decorators import *

lldbinline.MakeInlineTest(__file__, globals(),
decorators=[swiftTest,skipUnlessDarwin,
expectedFailureAll(bugnumber="rdar://60396797",
setting=('symbols.use-swift-clangimporter', 'false'))
])
decorators=[swiftTest,skipUnlessDarwin])