blob: ad23b0727450a9ac330dc9d55d7e1fae5f68d050 [file] [edit]
//===---------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "LibStdcpp.h"
#include "lldb/DataFormatters/TypeSynthetic.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/ValueObject/ValueObject.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/Support/Error.h"
using namespace lldb;
namespace lldb_private::formatters {
class LibStdcppAtomicSyntheticFrontEnd final
: public SyntheticChildrenFrontEnd {
public:
explicit LibStdcppAtomicSyntheticFrontEnd(ValueObject &valobj)
: SyntheticChildrenFrontEnd(valobj) {}
llvm::Expected<uint32_t> CalculateNumChildren() override {
if (!m_inner)
return llvm::createStringError("Invalid atomic ValueObject.");
return 1;
}
ValueObjectSP GetChildAtIndex(uint32_t idx) override {
if (idx == 0 && m_inner)
return m_inner->GetSP()->Clone(k_inner_name);
return {};
}
lldb::ChildCacheState Update() override {
if (ValueObjectSP value = ContainerFieldName(m_backend)) {
// show the Type, instead of std::__atomic_base<Type>::__Type_type.
value = value->Cast(value->GetCompilerType().GetCanonicalType());
m_inner = value.get();
}
return lldb::ChildCacheState::eRefetch;
}
llvm::Expected<size_t>
GetIndexOfChildWithName(llvm::StringRef name) override {
if (name == k_inner_name)
return 0;
return llvm::createStringErrorV("Type has no child named '{}'", name);
}
static ValueObjectSP ContainerFieldName(ValueObject &backend_syn) {
const ValueObjectSP non_synthetic = backend_syn.GetNonSyntheticValue();
if (!non_synthetic)
return {};
ValueObject &backend = *non_synthetic;
const CompilerType type = backend.GetCompilerType();
if (!type || type.GetNumTemplateArguments() == 0)
return {};
const CompilerType first_type = type.GetTypeTemplateArgument(0);
if (!first_type)
return {};
if (first_type.IsBoolean())
return backend.GetChildAtNamePath({"_M_base", "_M_i"});
const uint32_t float_mask = lldb::eTypeIsFloat | lldb::eTypeIsBuiltIn;
if ((first_type.GetTypeInfo() & float_mask) == float_mask) {
// added float types specialization in c++20
if (const auto child = backend.GetChildMemberWithName("_M_fp"))
return child;
return backend.GetChildMemberWithName("_M_i");
}
if (first_type.IsPointerType())
return backend.GetChildAtNamePath({"_M_b", "_M_p"});
const auto first_typename = first_type.GetDisplayTypeName().GetStringRef();
if (first_typename.starts_with("std::shared_ptr<") ||
first_typename.starts_with("std::weak_ptr<"))
return backend.GetChildAtNamePath({"_M_impl", "_M_ptr"});
return backend.GetChildMemberWithName("_M_i");
}
private:
inline static const ConstString k_inner_name = ConstString("Value");
ValueObject *m_inner = nullptr;
};
SyntheticChildrenFrontEnd *
LibStdcppAtomicSyntheticFrontEndCreator(CXXSyntheticChildren * /*unused*/,
const lldb::ValueObjectSP &valobj_sp) {
if (!valobj_sp)
return nullptr;
const ValueObjectSP member =
LibStdcppAtomicSyntheticFrontEnd::ContainerFieldName(*valobj_sp);
if (!member)
return nullptr;
return new LibStdcppAtomicSyntheticFrontEnd(*valobj_sp);
}
bool LibStdcppAtomicSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options) {
if (const ValueObjectSP atomic_value =
LibStdcppAtomicSyntheticFrontEnd::ContainerFieldName(valobj)) {
std::string summary;
if (atomic_value->GetSummaryAsCString(summary, options) &&
!summary.empty()) {
stream << summary;
return true;
}
ValueObject *aparent = atomic_value->GetParent();
if (aparent && aparent->GetName() == "_M_impl") {
return LibStdcppSmartPointerSummaryProvider(*aparent, stream, options,
/*is_atomic_child=*/true);
}
}
return false;
}
} // namespace lldb_private::formatters