| //===-- TypeSynthetic.h -----------------------------------------*- C++ -*-===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef lldb_TypeSynthetic_h_ |
| #define lldb_TypeSynthetic_h_ |
| |
| #include <stdint.h> |
| |
| #include <functional> |
| #include <initializer_list> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "lldb/lldb-enumerations.h" |
| #include "lldb/lldb-public.h" |
| |
| #include "lldb/Core/ValueObject.h" |
| #include "lldb/Utility/StructuredData.h" |
| |
| namespace lldb_private { |
| class SyntheticChildrenFrontEnd { |
| protected: |
| ValueObject &m_backend; |
| |
| void SetValid(bool valid) { m_valid = valid; } |
| |
| bool IsValid() { return m_valid; } |
| |
| public: |
| SyntheticChildrenFrontEnd(ValueObject &backend) |
| : m_backend(backend), m_valid(true) {} |
| |
| virtual ~SyntheticChildrenFrontEnd() = default; |
| |
| virtual size_t CalculateNumChildren() = 0; |
| |
| virtual size_t CalculateNumChildren(uint32_t max) { |
| auto count = CalculateNumChildren(); |
| return count <= max ? count : max; |
| } |
| |
| virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx) = 0; |
| |
| virtual size_t GetIndexOfChildWithName(ConstString name) = 0; |
| |
| // this function is assumed to always succeed and it if fails, the front-end |
| // should know to deal with it in the correct way (most probably, by refusing |
| // to return any children) the return value of Update() should actually be |
| // interpreted as "ValueObjectSyntheticFilter cache is good/bad" if =true, |
| // ValueObjectSyntheticFilter is allowed to use the children it fetched |
| // previously and cached if =false, ValueObjectSyntheticFilter must throw |
| // away its cache, and query again for children |
| virtual bool Update() = 0; |
| |
| // if this function returns false, then CalculateNumChildren() MUST return 0 |
| // since UI frontends might validly decide not to inquire for children given |
| // a false return value from this call if it returns true, then |
| // CalculateNumChildren() can return any number >= 0 (0 being valid) it |
| // should if at all possible be more efficient than CalculateNumChildren() |
| virtual bool MightHaveChildren() = 0; |
| |
| // if this function returns a non-null ValueObject, then the returned |
| // ValueObject will stand for this ValueObject whenever a "value" request is |
| // made to this ValueObject |
| virtual lldb::ValueObjectSP GetSyntheticValue() { return nullptr; } |
| |
| // if this function returns a non-empty ConstString, then clients are |
| // expected to use the return as the name of the type of this ValueObject for |
| // display purposes |
| virtual ConstString GetSyntheticTypeName() { return ConstString(); } |
| |
| typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; |
| typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer; |
| |
| protected: |
| lldb::ValueObjectSP |
| CreateValueObjectFromExpression(llvm::StringRef name, |
| llvm::StringRef expression, |
| const ExecutionContext &exe_ctx); |
| |
| lldb::ValueObjectSP |
| CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, |
| const ExecutionContext &exe_ctx, |
| CompilerType type); |
| |
| lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, |
| const DataExtractor &data, |
| const ExecutionContext &exe_ctx, |
| CompilerType type); |
| |
| private: |
| bool m_valid; |
| DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd); |
| }; |
| |
| class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd { |
| public: |
| SyntheticValueProviderFrontEnd(ValueObject &backend) |
| : SyntheticChildrenFrontEnd(backend) {} |
| |
| ~SyntheticValueProviderFrontEnd() override = default; |
| |
| size_t CalculateNumChildren() override { return 0; } |
| |
| lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } |
| |
| size_t GetIndexOfChildWithName(ConstString name) override { |
| return UINT32_MAX; |
| } |
| |
| bool Update() override { return false; } |
| |
| bool MightHaveChildren() override { return false; } |
| |
| lldb::ValueObjectSP GetSyntheticValue() override = 0; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SyntheticValueProviderFrontEnd); |
| }; |
| |
| class SyntheticChildren { |
| public: |
| class Flags { |
| public: |
| Flags() : m_flags(lldb::eTypeOptionCascade) {} |
| |
| Flags(const Flags &other) : m_flags(other.m_flags) {} |
| |
| Flags(uint32_t value) : m_flags(value) {} |
| |
| Flags &operator=(const Flags &rhs) { |
| if (&rhs != this) |
| m_flags = rhs.m_flags; |
| |
| return *this; |
| } |
| |
| Flags &operator=(const uint32_t &rhs) { |
| m_flags = rhs; |
| return *this; |
| } |
| |
| Flags &Clear() { |
| m_flags = 0; |
| return *this; |
| } |
| |
| bool GetCascades() const { |
| return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; |
| } |
| |
| Flags &SetCascades(bool value = true) { |
| if (value) |
| m_flags |= lldb::eTypeOptionCascade; |
| else |
| m_flags &= ~lldb::eTypeOptionCascade; |
| return *this; |
| } |
| |
| bool GetSkipPointers() const { |
| return (m_flags & lldb::eTypeOptionSkipPointers) == |
| lldb::eTypeOptionSkipPointers; |
| } |
| |
| Flags &SetSkipPointers(bool value = true) { |
| if (value) |
| m_flags |= lldb::eTypeOptionSkipPointers; |
| else |
| m_flags &= ~lldb::eTypeOptionSkipPointers; |
| return *this; |
| } |
| |
| bool GetSkipReferences() const { |
| return (m_flags & lldb::eTypeOptionSkipReferences) == |
| lldb::eTypeOptionSkipReferences; |
| } |
| |
| Flags &SetSkipReferences(bool value = true) { |
| if (value) |
| m_flags |= lldb::eTypeOptionSkipReferences; |
| else |
| m_flags &= ~lldb::eTypeOptionSkipReferences; |
| return *this; |
| } |
| |
| bool GetNonCacheable() const { |
| return (m_flags & lldb::eTypeOptionNonCacheable) == |
| lldb::eTypeOptionNonCacheable; |
| } |
| |
| Flags &SetNonCacheable(bool value = true) { |
| if (value) |
| m_flags |= lldb::eTypeOptionNonCacheable; |
| else |
| m_flags &= ~lldb::eTypeOptionNonCacheable; |
| return *this; |
| } |
| |
| bool GetFrontEndWantsDereference() const { |
| return (m_flags & lldb::eTypeOptionFrontEndWantsDereference) == |
| lldb::eTypeOptionFrontEndWantsDereference; |
| } |
| |
| Flags &SetFrontEndWantsDereference(bool value = true) { |
| if (value) |
| m_flags |= lldb::eTypeOptionFrontEndWantsDereference; |
| else |
| m_flags &= ~lldb::eTypeOptionFrontEndWantsDereference; |
| return *this; |
| } |
| |
| uint32_t GetValue() { return m_flags; } |
| |
| void SetValue(uint32_t value) { m_flags = value; } |
| |
| private: |
| uint32_t m_flags; |
| }; |
| |
| SyntheticChildren(const Flags &flags) : m_flags(flags) {} |
| |
| virtual ~SyntheticChildren() = default; |
| |
| bool Cascades() const { return m_flags.GetCascades(); } |
| |
| bool SkipsPointers() const { return m_flags.GetSkipPointers(); } |
| |
| bool SkipsReferences() const { return m_flags.GetSkipReferences(); } |
| |
| bool NonCacheable() const { return m_flags.GetNonCacheable(); } |
| |
| bool WantsDereference() const { return m_flags.GetFrontEndWantsDereference();} |
| |
| void SetCascades(bool value) { m_flags.SetCascades(value); } |
| |
| void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } |
| |
| void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } |
| |
| void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } |
| |
| uint32_t GetOptions() { return m_flags.GetValue(); } |
| |
| void SetOptions(uint32_t value) { m_flags.SetValue(value); } |
| |
| virtual bool IsScripted() = 0; |
| |
| virtual std::string GetDescription() = 0; |
| |
| virtual SyntheticChildrenFrontEnd::AutoPointer |
| GetFrontEnd(ValueObject &backend) = 0; |
| |
| typedef std::shared_ptr<SyntheticChildren> SharedPointer; |
| |
| uint32_t &GetRevision() { return m_my_revision; } |
| |
| protected: |
| uint32_t m_my_revision; |
| Flags m_flags; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SyntheticChildren); |
| }; |
| |
| class TypeFilterImpl : public SyntheticChildren { |
| std::vector<std::string> m_expression_paths; |
| |
| public: |
| TypeFilterImpl(const SyntheticChildren::Flags &flags) |
| : SyntheticChildren(flags), m_expression_paths() {} |
| |
| TypeFilterImpl(const SyntheticChildren::Flags &flags, |
| const std::initializer_list<const char *> items) |
| : SyntheticChildren(flags), m_expression_paths() { |
| for (auto path : items) |
| AddExpressionPath(path); |
| } |
| |
| void AddExpressionPath(const char *path) { |
| AddExpressionPath(std::string(path)); |
| } |
| |
| void Clear() { m_expression_paths.clear(); } |
| |
| size_t GetCount() const { return m_expression_paths.size(); } |
| |
| const char *GetExpressionPathAtIndex(size_t i) const { |
| return m_expression_paths[i].c_str(); |
| } |
| |
| bool SetExpressionPathAtIndex(size_t i, const char *path) { |
| return SetExpressionPathAtIndex(i, std::string(path)); |
| } |
| |
| void AddExpressionPath(const std::string &path); |
| |
| bool SetExpressionPathAtIndex(size_t i, const std::string &path); |
| |
| bool IsScripted() override { return false; } |
| |
| std::string GetDescription() override; |
| |
| class FrontEnd : public SyntheticChildrenFrontEnd { |
| public: |
| FrontEnd(TypeFilterImpl *flt, ValueObject &backend) |
| : SyntheticChildrenFrontEnd(backend), filter(flt) {} |
| |
| ~FrontEnd() override = default; |
| |
| size_t CalculateNumChildren() override { return filter->GetCount(); } |
| |
| lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { |
| if (idx >= filter->GetCount()) |
| return lldb::ValueObjectSP(); |
| return m_backend.GetSyntheticExpressionPathChild( |
| filter->GetExpressionPathAtIndex(idx), true); |
| } |
| |
| bool Update() override { return false; } |
| |
| bool MightHaveChildren() override { return filter->GetCount() > 0; } |
| |
| size_t GetIndexOfChildWithName(ConstString name) override; |
| |
| typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; |
| |
| private: |
| TypeFilterImpl *filter; |
| |
| DISALLOW_COPY_AND_ASSIGN(FrontEnd); |
| }; |
| |
| SyntheticChildrenFrontEnd::AutoPointer |
| GetFrontEnd(ValueObject &backend) override { |
| return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); |
| } |
| |
| typedef std::shared_ptr<TypeFilterImpl> SharedPointer; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl); |
| }; |
| |
| class CXXSyntheticChildren : public SyntheticChildren { |
| public: |
| typedef std::function<SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, |
| lldb::ValueObjectSP)> |
| CreateFrontEndCallback; |
| CXXSyntheticChildren(const SyntheticChildren::Flags &flags, |
| const char *description, CreateFrontEndCallback callback) |
| : SyntheticChildren(flags), m_create_callback(callback), |
| m_description(description ? description : "") {} |
| |
| bool IsScripted() override { return false; } |
| |
| std::string GetDescription() override; |
| |
| SyntheticChildrenFrontEnd::AutoPointer |
| GetFrontEnd(ValueObject &backend) override { |
| return SyntheticChildrenFrontEnd::AutoPointer( |
| m_create_callback(this, backend.GetSP())); |
| } |
| |
| protected: |
| CreateFrontEndCallback m_create_callback; |
| std::string m_description; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren); |
| }; |
| |
| class ScriptedSyntheticChildren : public SyntheticChildren { |
| std::string m_python_class; |
| std::string m_python_code; |
| |
| public: |
| ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags, |
| const char *pclass, const char *pcode = nullptr) |
| : SyntheticChildren(flags), m_python_class(), m_python_code() { |
| if (pclass) |
| m_python_class = pclass; |
| if (pcode) |
| m_python_code = pcode; |
| } |
| |
| const char *GetPythonClassName() { return m_python_class.c_str(); } |
| |
| const char *GetPythonCode() { return m_python_code.c_str(); } |
| |
| void SetPythonClassName(const char *fname) { |
| m_python_class.assign(fname); |
| m_python_code.clear(); |
| } |
| |
| void SetPythonCode(const char *script) { m_python_code.assign(script); } |
| |
| std::string GetDescription() override; |
| |
| bool IsScripted() override { return true; } |
| |
| class FrontEnd : public SyntheticChildrenFrontEnd { |
| public: |
| FrontEnd(std::string pclass, ValueObject &backend); |
| |
| ~FrontEnd() override; |
| |
| bool IsValid(); |
| |
| size_t CalculateNumChildren() override; |
| |
| size_t CalculateNumChildren(uint32_t max) override; |
| |
| lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; |
| |
| bool Update() override; |
| |
| bool MightHaveChildren() override; |
| |
| size_t GetIndexOfChildWithName(ConstString name) override; |
| |
| lldb::ValueObjectSP GetSyntheticValue() override; |
| |
| ConstString GetSyntheticTypeName() override; |
| |
| typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; |
| |
| private: |
| std::string m_python_class; |
| StructuredData::ObjectSP m_wrapper_sp; |
| ScriptInterpreter *m_interpreter; |
| |
| DISALLOW_COPY_AND_ASSIGN(FrontEnd); |
| }; |
| |
| SyntheticChildrenFrontEnd::AutoPointer |
| GetFrontEnd(ValueObject &backend) override { |
| auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer( |
| new FrontEnd(m_python_class, backend)); |
| if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid()) |
| return synth_ptr; |
| return nullptr; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren); |
| }; |
| } // namespace lldb_private |
| |
| #endif // lldb_TypeSynthetic_h_ |