1212
1313#include " SwiftFormatters.h"
1414#include " Plugins/Language/Swift/SwiftStringIndex.h"
15+ #include " Plugins/LanguageRuntime/Swift/ReflectionContextInterface.h"
1516#include " Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"
1617#include " Plugins/TypeSystem/Clang/TypeSystemClang.h"
1718#include " lldb/Core/ValueObject.h"
2021#include " lldb/Target/Process.h"
2122#include " lldb/Utility/ConstString.h"
2223#include " lldb/Utility/DataBufferHeap.h"
24+ #include " lldb/Utility/LLDBLog.h"
25+ #include " lldb/Utility/Log.h"
2326#include " lldb/Utility/Status.h"
2427#include " lldb/Utility/Timer.h"
2528#include " lldb/lldb-enumerations.h"
2629#include " swift/AST/Types.h"
2730#include " swift/Demangling/ManglingMacros.h"
31+ #include " llvm/ADT/STLExtras.h"
2832#include " llvm/ADT/StringRef.h"
33+ #include " llvm/Support/FormatAdapters.h"
34+ #include " llvm/Support/raw_ostream.h"
2935#include < optional>
3036
3137// FIXME: we should not need this
@@ -721,6 +727,7 @@ bool lldb_private::formatters::swift::BuiltinObjC_SummaryProvider(
721727namespace lldb_private {
722728namespace formatters {
723729namespace swift {
730+
724731class EnumSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
725732public:
726733 EnumSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
@@ -736,6 +743,112 @@ class EnumSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
736743 ConstString m_element_name;
737744 size_t m_child_index;
738745};
746+
747+ // / Synthetic provider for `Swift.Task`.
748+ // /
749+ // / As seen by lldb, a `Task` instance is an opaque pointer, with neither type
750+ // / metadata nor an AST to describe it. To implement this synthetic provider, a
751+ // / `Task`'s state is retrieved from a `ReflectionContext`, and that data is
752+ // / used to manually construct `ValueObject` children.
753+ class TaskSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
754+ public:
755+ TaskSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp)
756+ : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
757+
758+ constexpr static StringLiteral TaskChildren[] = {
759+ " isChildTask" , " isFuture" , " isGroupChildTask" ,
760+ " isAsyncLetTask" , " isCancelled" , " isStatusRecordLocked" ,
761+ " isEscalated" , " isEnqueued" , " isRunning" ,
762+ };
763+
764+ llvm::Expected<uint32_t > CalculateNumChildren () override {
765+ auto count = ArrayRef (TaskChildren).size ();
766+ return m_task_info.hasIsRunning ? count : count - 1 ;
767+ }
768+
769+ lldb::ValueObjectSP GetChildAtIndex (uint32_t idx) override {
770+ auto target_sp = m_backend.GetTargetSP ();
771+ #define RETURN_CHILD (FIELD, NAME ) \
772+ if (!FIELD) \
773+ FIELD = ValueObject::CreateValueObjectFromBool (target_sp, \
774+ m_task_info.NAME , #NAME); \
775+ return FIELD
776+
777+ switch (idx) {
778+ case 0 :
779+ RETURN_CHILD (m_is_child_task_sp, isChildTask);
780+ case 1 :
781+ RETURN_CHILD (m_is_future_sp, isFuture);
782+ case 2 :
783+ RETURN_CHILD (m_is_group_child_task_sp, isGroupChildTask);
784+ case 3 :
785+ RETURN_CHILD (m_is_async_let_task_sp, isAsyncLetTask);
786+ case 4 :
787+ RETURN_CHILD (m_is_cancelled_sp, isCancelled);
788+ case 5 :
789+ RETURN_CHILD (m_is_status_record_locked_sp, isStatusRecordLocked);
790+ case 6 :
791+ RETURN_CHILD (m_is_escalated_sp, isEscalated);
792+ case 7 :
793+ RETURN_CHILD (m_is_enqueued_sp, isEnqueued);
794+ case 8 :
795+ RETURN_CHILD (m_is_running_sp, isRunning);
796+ default :
797+ return {};
798+ }
799+
800+ #undef RETURN_CHILD
801+ }
802+
803+ lldb::ChildCacheState Update () override {
804+ if (auto *runtime = SwiftLanguageRuntime::Get (m_backend.GetProcessSP ())) {
805+ ThreadSafeReflectionContext reflection_ctx =
806+ runtime->GetReflectionContext ();
807+ ValueObjectSP task_obj_sp = m_backend.GetChildMemberWithName (" _task" );
808+ uint64_t task_ptr = task_obj_sp->GetValueAsUnsigned (LLDB_INVALID_ADDRESS);
809+ if (task_ptr != LLDB_INVALID_ADDRESS) {
810+ llvm::Expected<ReflectionContextInterface::AsyncTaskInfo> task_info =
811+ reflection_ctx->asyncTaskInfo (task_ptr);
812+ if (auto err = task_info.takeError ()) {
813+ LLDB_LOG (GetLog (LLDBLog::DataFormatters | LLDBLog::Types),
814+ " could not get info for async task {0:x}: {1}" , task_ptr,
815+ fmt_consume (std::move (err)));
816+ } else {
817+ m_task_info = *task_info;
818+ for (auto child :
819+ {m_is_child_task_sp, m_is_future_sp, m_is_group_child_task_sp,
820+ m_is_async_let_task_sp, m_is_cancelled_sp,
821+ m_is_status_record_locked_sp, m_is_escalated_sp,
822+ m_is_enqueued_sp, m_is_running_sp})
823+ child.reset ();
824+ }
825+ }
826+ }
827+ return ChildCacheState::eRefetch;
828+ }
829+
830+ bool MightHaveChildren () override { return true ; }
831+
832+ size_t GetIndexOfChildWithName (ConstString name) override {
833+ ArrayRef children = TaskChildren;
834+ auto it = llvm::find (children, name);
835+ if (it == children.end ())
836+ return UINT32_MAX;
837+ return std::distance (children.begin (), it);
838+ }
839+
840+ private:
841+ ReflectionContextInterface::AsyncTaskInfo m_task_info;
842+ ValueObjectSP m_is_child_task_sp;
843+ ValueObjectSP m_is_future_sp;
844+ ValueObjectSP m_is_group_child_task_sp;
845+ ValueObjectSP m_is_async_let_task_sp;
846+ ValueObjectSP m_is_cancelled_sp;
847+ ValueObjectSP m_is_status_record_locked_sp;
848+ ValueObjectSP m_is_escalated_sp;
849+ ValueObjectSP m_is_enqueued_sp;
850+ ValueObjectSP m_is_running_sp;
851+ };
739852}
740853}
741854}
@@ -794,6 +907,14 @@ lldb_private::formatters::swift::EnumSyntheticFrontEndCreator(
794907 return (new EnumSyntheticFrontEnd (valobj_sp));
795908}
796909
910+ SyntheticChildrenFrontEnd *
911+ lldb_private::formatters::swift::TaskSyntheticFrontEndCreator (
912+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
913+ if (!valobj_sp)
914+ return NULL ;
915+ return new TaskSyntheticFrontEnd (valobj_sp);
916+ }
917+
797918bool lldb_private::formatters::swift::ObjC_Selector_SummaryProvider (
798919 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
799920 LLDB_SCOPED_TIMER ();
0 commit comments