//===-- TypeSynthetic.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef lldb_TypeSynthetic_h_ #define lldb_TypeSynthetic_h_ // C Includes #include // C++ Includes #include #include // Other libraries and framework includes // Project includes #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" #include "lldb/Core/ValueObject.h" #include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Symbol/Type.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 () { } virtual size_t CalculateNumChildren () = 0; virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx) = 0; virtual size_t GetIndexOfChildWithName (const 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; typedef std::shared_ptr SharedPointer; typedef std::unique_ptr AutoPointer; private: bool m_valid; DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd); }; 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; } 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 () { } bool Cascades () const { return m_flags.GetCascades(); } bool SkipsPointers () const { return m_flags.GetSkipPointers(); } bool SkipsReferences () const { return m_flags.GetSkipReferences(); } void SetCascades (bool value) { m_flags.SetCascades(value); } void SetSkipsPointers (bool value) { m_flags.SetSkipPointers(value); } void SetSkipsReferences (bool value) { m_flags.SetSkipReferences(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 SharedPointer; typedef bool(*SyntheticChildrenCallback)(void*, ConstString, const 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 m_expression_paths; public: TypeFilterImpl(const SyntheticChildren::Flags& flags) : SyntheticChildren(flags), m_expression_paths() { } TypeFilterImpl(const SyntheticChildren::Flags& flags, const std::initializer_list 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 need_add_dot = true; if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[') need_add_dot = false; // add a '.' symbol to help forgetful users if(!need_add_dot) m_expression_paths.push_back(path); else m_expression_paths.push_back(std::string(".") + path); } bool SetExpressionPathAtIndex (size_t i, const std::string& path) { if (i >= GetCount()) return false; bool need_add_dot = true; if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[') need_add_dot = false; // add a '.' symbol to help forgetful users if(!need_add_dot) m_expression_paths[i] = path; else m_expression_paths[i] = std::string(".") + path; return true; } bool IsScripted () { return false; } std::string GetDescription (); class FrontEnd : public SyntheticChildrenFrontEnd { private: TypeFilterImpl* filter; public: FrontEnd(TypeFilterImpl* flt, ValueObject &backend) : SyntheticChildrenFrontEnd(backend), filter(flt) {} virtual ~FrontEnd () { } virtual size_t CalculateNumChildren () { return filter->GetCount(); } virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx) { if (idx >= filter->GetCount()) return lldb::ValueObjectSP(); return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true); } virtual bool Update() { return false; } virtual bool MightHaveChildren () { return filter->GetCount() > 0; } virtual size_t GetIndexOfChildWithName (const ConstString &name) { const char* name_cstr = name.GetCString(); for (size_t i = 0; i < filter->GetCount(); i++) { const char* expr_cstr = filter->GetExpressionPathAtIndex(i); if (expr_cstr) { if (*expr_cstr == '.') expr_cstr++; else if (*expr_cstr == '-' && *(expr_cstr+1) == '>') expr_cstr += 2; } if (!::strcmp(name_cstr, expr_cstr)) return i; } return UINT32_MAX; } typedef std::shared_ptr SharedPointer; private: DISALLOW_COPY_AND_ASSIGN(FrontEnd); }; virtual SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd(ValueObject &backend) { return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); } private: DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl); }; class CXXSyntheticChildren : public SyntheticChildren { public: typedef SyntheticChildrenFrontEnd* (*CreateFrontEndCallback) (CXXSyntheticChildren*, lldb::ValueObjectSP); protected: CreateFrontEndCallback m_create_callback; std::string m_description; public: CXXSyntheticChildren (const SyntheticChildren::Flags& flags, const char* description, CreateFrontEndCallback callback) : SyntheticChildren(flags), m_create_callback(callback), m_description(description ? description : "") { } bool IsScripted () { return false; } std::string GetDescription (); virtual SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd (ValueObject &backend) { return SyntheticChildrenFrontEnd::AutoPointer(m_create_callback(this, backend.GetSP())); } private: DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren); }; #ifndef LLDB_DISABLE_PYTHON 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 = NULL) : 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 (); bool IsScripted () { return true; } class FrontEnd : public SyntheticChildrenFrontEnd { private: std::string m_python_class; lldb::ScriptInterpreterObjectSP m_wrapper_sp; ScriptInterpreter *m_interpreter; public: FrontEnd (std::string pclass, ValueObject &backend); bool IsValid () { return m_wrapper_sp.get() != nullptr && m_wrapper_sp->operator bool() && m_interpreter != nullptr; } virtual ~FrontEnd (); virtual size_t CalculateNumChildren () { if (!m_wrapper_sp || m_interpreter == NULL) return 0; return m_interpreter->CalculateNumChildren(m_wrapper_sp); } virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx); virtual bool Update () { if (!m_wrapper_sp || m_interpreter == NULL) return false; return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp); } virtual bool MightHaveChildren () { if (!m_wrapper_sp || m_interpreter == NULL) return false; return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp); } virtual size_t GetIndexOfChildWithName (const ConstString &name) { if (!m_wrapper_sp || m_interpreter == NULL) return UINT32_MAX; return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString()); } typedef std::shared_ptr SharedPointer; private: DISALLOW_COPY_AND_ASSIGN(FrontEnd); }; virtual SyntheticChildrenFrontEnd::AutoPointer GetFrontEnd(ValueObject &backend) { auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(m_python_class, backend)); if (synth_ptr && ((FrontEnd*)synth_ptr.get())->IsValid()) return synth_ptr; return NULL; } private: DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren); }; #endif } // namespace lldb_private #endif // lldb_TypeSynthetic_h_