TypeSynthetic.h revision 263363
1//===-- TypeSynthetic.h -------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef lldb_TypeSynthetic_h_
11#define lldb_TypeSynthetic_h_
12
13// C Includes
14#include <stdint.h>
15
16// C++ Includes
17#include <string>
18#include <vector>
19
20// Other libraries and framework includes
21
22// Project includes
23#include "lldb/lldb-public.h"
24#include "lldb/lldb-enumerations.h"
25
26#include "lldb/Core/ValueObject.h"
27#include "lldb/Interpreter/ScriptInterpreterPython.h"
28#include "lldb/Symbol/Type.h"
29
30namespace lldb_private {
31    class SyntheticChildrenFrontEnd
32    {
33    protected:
34        ValueObject &m_backend;
35    public:
36
37        SyntheticChildrenFrontEnd (ValueObject &backend) :
38        m_backend(backend)
39        {}
40
41        virtual
42        ~SyntheticChildrenFrontEnd ()
43        {
44        }
45
46        virtual size_t
47        CalculateNumChildren () = 0;
48
49        virtual lldb::ValueObjectSP
50        GetChildAtIndex (size_t idx) = 0;
51
52        virtual size_t
53        GetIndexOfChildWithName (const ConstString &name) = 0;
54
55        // this function is assumed to always succeed and it if fails, the front-end should know to deal
56        // with it in the correct way (most probably, by refusing to return any children)
57        // the return value of Update() should actually be interpreted as "ValueObjectSyntheticFilter cache is good/bad"
58        // if =true, ValueObjectSyntheticFilter is allowed to use the children it fetched previously and cached
59        // if =false, ValueObjectSyntheticFilter must throw away its cache, and query again for children
60        virtual bool
61        Update () = 0;
62
63        // if this function returns false, then CalculateNumChildren() MUST return 0 since UI frontends
64        // might validly decide not to inquire for children given a false return value from this call
65        // if it returns true, then CalculateNumChildren() can return any number >= 0 (0 being valid)
66        // it should if at all possible be more efficient than CalculateNumChildren()
67        virtual bool
68        MightHaveChildren () = 0;
69
70        typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
71        typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer;
72
73    private:
74        DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd);
75    };
76
77    class SyntheticChildren
78    {
79    public:
80
81        class Flags
82        {
83        public:
84
85            Flags () :
86            m_flags (lldb::eTypeOptionCascade)
87            {}
88
89            Flags (const Flags& other) :
90            m_flags (other.m_flags)
91            {}
92
93            Flags (uint32_t value) :
94            m_flags (value)
95            {}
96
97            Flags&
98            operator = (const Flags& rhs)
99            {
100                if (&rhs != this)
101                    m_flags = rhs.m_flags;
102
103                return *this;
104            }
105
106            Flags&
107            operator = (const uint32_t& rhs)
108            {
109                m_flags = rhs;
110                return *this;
111            }
112
113            Flags&
114            Clear()
115            {
116                m_flags = 0;
117                return *this;
118            }
119
120            bool
121            GetCascades () const
122            {
123                return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
124            }
125
126            Flags&
127            SetCascades (bool value = true)
128            {
129                if (value)
130                    m_flags |= lldb::eTypeOptionCascade;
131                else
132                    m_flags &= ~lldb::eTypeOptionCascade;
133                return *this;
134            }
135
136            bool
137            GetSkipPointers () const
138            {
139                return (m_flags & lldb::eTypeOptionSkipPointers) == lldb::eTypeOptionSkipPointers;
140            }
141
142            Flags&
143            SetSkipPointers (bool value = true)
144            {
145                if (value)
146                    m_flags |= lldb::eTypeOptionSkipPointers;
147                else
148                    m_flags &= ~lldb::eTypeOptionSkipPointers;
149                return *this;
150            }
151
152            bool
153            GetSkipReferences () const
154            {
155                return (m_flags & lldb::eTypeOptionSkipReferences) == lldb::eTypeOptionSkipReferences;
156            }
157
158            Flags&
159            SetSkipReferences (bool value = true)
160            {
161                if (value)
162                    m_flags |= lldb::eTypeOptionSkipReferences;
163                else
164                    m_flags &= ~lldb::eTypeOptionSkipReferences;
165                return *this;
166            }
167
168            uint32_t
169            GetValue ()
170            {
171                return m_flags;
172            }
173
174            void
175            SetValue (uint32_t value)
176            {
177                m_flags = value;
178            }
179
180        private:
181            uint32_t m_flags;
182        };
183
184        SyntheticChildren (const Flags& flags) :
185        m_flags(flags)
186        {
187        }
188
189        virtual
190        ~SyntheticChildren ()
191        {
192        }
193
194        bool
195        Cascades () const
196        {
197            return m_flags.GetCascades();
198        }
199        bool
200        SkipsPointers () const
201        {
202            return m_flags.GetSkipPointers();
203        }
204        bool
205        SkipsReferences () const
206        {
207            return m_flags.GetSkipReferences();
208        }
209
210        void
211        SetCascades (bool value)
212        {
213            m_flags.SetCascades(value);
214        }
215
216        void
217        SetSkipsPointers (bool value)
218        {
219            m_flags.SetSkipPointers(value);
220        }
221
222        void
223        SetSkipsReferences (bool value)
224        {
225            m_flags.SetSkipReferences(value);
226        }
227
228        uint32_t
229        GetOptions ()
230        {
231            return m_flags.GetValue();
232        }
233
234        void
235        SetOptions (uint32_t value)
236        {
237            m_flags.SetValue(value);
238        }
239
240        virtual bool
241        IsScripted () = 0;
242
243        virtual std::string
244        GetDescription () = 0;
245
246        virtual SyntheticChildrenFrontEnd::AutoPointer
247        GetFrontEnd (ValueObject &backend) = 0;
248
249        typedef std::shared_ptr<SyntheticChildren> SharedPointer;
250        typedef bool(*SyntheticChildrenCallback)(void*, ConstString, const SyntheticChildren::SharedPointer&);
251
252        uint32_t&
253        GetRevision ()
254        {
255            return m_my_revision;
256        }
257
258    protected:
259        uint32_t m_my_revision;
260        Flags m_flags;
261
262    private:
263        DISALLOW_COPY_AND_ASSIGN(SyntheticChildren);
264    };
265
266    class TypeFilterImpl : public SyntheticChildren
267    {
268        std::vector<std::string> m_expression_paths;
269    public:
270        TypeFilterImpl(const SyntheticChildren::Flags& flags) :
271        SyntheticChildren(flags),
272        m_expression_paths()
273        {
274        }
275
276        TypeFilterImpl(const SyntheticChildren::Flags& flags,
277                       const std::initializer_list<const char*> items) :
278        SyntheticChildren(flags),
279        m_expression_paths()
280        {
281            for (auto path : items)
282                AddExpressionPath (path);
283        }
284
285        void
286        AddExpressionPath (const char* path)
287        {
288            AddExpressionPath(std::string(path));
289        }
290
291        void
292        Clear()
293        {
294            m_expression_paths.clear();
295        }
296
297        size_t
298        GetCount() const
299        {
300            return m_expression_paths.size();
301        }
302
303        const char*
304        GetExpressionPathAtIndex(size_t i) const
305        {
306            return m_expression_paths[i].c_str();
307        }
308
309        bool
310        SetExpressionPathAtIndex (size_t i, const char* path)
311        {
312            return SetExpressionPathAtIndex(i, std::string(path));
313        }
314
315        void
316        AddExpressionPath (const std::string& path)
317        {
318            bool need_add_dot = true;
319            if (path[0] == '.' ||
320                (path[0] == '-' && path[1] == '>') ||
321                path[0] == '[')
322                need_add_dot = false;
323            // add a '.' symbol to help forgetful users
324            if(!need_add_dot)
325                m_expression_paths.push_back(path);
326            else
327                m_expression_paths.push_back(std::string(".") + path);
328        }
329
330        bool
331        SetExpressionPathAtIndex (size_t i, const std::string& path)
332        {
333            if (i >= GetCount())
334                return false;
335            bool need_add_dot = true;
336            if (path[0] == '.' ||
337                (path[0] == '-' && path[1] == '>') ||
338                path[0] == '[')
339                need_add_dot = false;
340            // add a '.' symbol to help forgetful users
341            if(!need_add_dot)
342                m_expression_paths[i] = path;
343            else
344                m_expression_paths[i] = std::string(".") + path;
345            return true;
346        }
347
348        bool
349        IsScripted ()
350        {
351            return false;
352        }
353
354        std::string
355        GetDescription ();
356
357        class FrontEnd : public SyntheticChildrenFrontEnd
358        {
359        private:
360            TypeFilterImpl* filter;
361        public:
362
363            FrontEnd(TypeFilterImpl* flt,
364                     ValueObject &backend) :
365            SyntheticChildrenFrontEnd(backend),
366            filter(flt)
367            {}
368
369            virtual
370            ~FrontEnd ()
371            {
372            }
373
374            virtual size_t
375            CalculateNumChildren ()
376            {
377                return filter->GetCount();
378            }
379
380            virtual lldb::ValueObjectSP
381            GetChildAtIndex (size_t idx)
382            {
383                if (idx >= filter->GetCount())
384                    return lldb::ValueObjectSP();
385                return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true);
386            }
387
388            virtual bool
389            Update() { return false; }
390
391            virtual bool
392            MightHaveChildren ()
393            {
394                return filter->GetCount() > 0;
395            }
396
397            virtual size_t
398            GetIndexOfChildWithName (const ConstString &name)
399            {
400                const char* name_cstr = name.GetCString();
401                for (size_t i = 0; i < filter->GetCount(); i++)
402                {
403                    const char* expr_cstr = filter->GetExpressionPathAtIndex(i);
404                    if (expr_cstr)
405                    {
406                        if (*expr_cstr == '.')
407                            expr_cstr++;
408                        else if (*expr_cstr == '-' && *(expr_cstr+1) == '>')
409                            expr_cstr += 2;
410                    }
411                    if (!::strcmp(name_cstr, expr_cstr))
412                        return i;
413                }
414                return UINT32_MAX;
415            }
416
417            typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
418
419        private:
420            DISALLOW_COPY_AND_ASSIGN(FrontEnd);
421        };
422
423        virtual SyntheticChildrenFrontEnd::AutoPointer
424        GetFrontEnd(ValueObject &backend)
425        {
426            return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend));
427        }
428
429    private:
430        DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl);
431    };
432
433    class CXXSyntheticChildren : public SyntheticChildren
434    {
435    public:
436        typedef SyntheticChildrenFrontEnd* (*CreateFrontEndCallback) (CXXSyntheticChildren*, lldb::ValueObjectSP);
437    protected:
438        CreateFrontEndCallback m_create_callback;
439        std::string m_description;
440    public:
441        CXXSyntheticChildren (const SyntheticChildren::Flags& flags,
442                              const char* description,
443                              CreateFrontEndCallback callback) :
444        SyntheticChildren(flags),
445        m_create_callback(callback),
446        m_description(description ? description : "")
447        {
448        }
449
450        bool
451        IsScripted ()
452        {
453            return false;
454        }
455
456        std::string
457        GetDescription ();
458
459        virtual SyntheticChildrenFrontEnd::AutoPointer
460        GetFrontEnd (ValueObject &backend)
461        {
462            return SyntheticChildrenFrontEnd::AutoPointer(m_create_callback(this, backend.GetSP()));
463        }
464
465    private:
466        DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren);
467    };
468
469#ifndef LLDB_DISABLE_PYTHON
470
471    class ScriptedSyntheticChildren : public SyntheticChildren
472    {
473        std::string m_python_class;
474        std::string m_python_code;
475    public:
476
477        ScriptedSyntheticChildren (const SyntheticChildren::Flags& flags,
478                                   const char* pclass,
479                                   const char* pcode = NULL) :
480        SyntheticChildren(flags),
481        m_python_class(),
482        m_python_code()
483        {
484            if (pclass)
485                m_python_class = pclass;
486            if (pcode)
487                m_python_code = pcode;
488        }
489
490        const char*
491        GetPythonClassName ()
492        {
493            return m_python_class.c_str();
494        }
495
496        const char*
497        GetPythonCode ()
498        {
499            return m_python_code.c_str();
500        }
501
502        void
503        SetPythonClassName (const char* fname)
504        {
505            m_python_class.assign(fname);
506            m_python_code.clear();
507        }
508
509        void
510        SetPythonCode (const char* script)
511        {
512            m_python_code.assign(script);
513        }
514
515        std::string
516        GetDescription ();
517
518        bool
519        IsScripted ()
520        {
521            return true;
522        }
523
524        class FrontEnd : public SyntheticChildrenFrontEnd
525        {
526        private:
527            std::string m_python_class;
528            lldb::ScriptInterpreterObjectSP m_wrapper_sp;
529            ScriptInterpreter *m_interpreter;
530        public:
531
532            FrontEnd (std::string pclass,
533                      ValueObject &backend);
534
535            bool
536            IsValid ()
537            {
538                return m_wrapper_sp.get() != nullptr && m_wrapper_sp->operator bool() && m_interpreter != nullptr;
539            }
540
541            virtual
542            ~FrontEnd ();
543
544            virtual size_t
545            CalculateNumChildren ()
546            {
547                if (!m_wrapper_sp || m_interpreter == NULL)
548                    return 0;
549                return m_interpreter->CalculateNumChildren(m_wrapper_sp);
550            }
551
552            virtual lldb::ValueObjectSP
553            GetChildAtIndex (size_t idx);
554
555            virtual bool
556            Update ()
557            {
558                if (!m_wrapper_sp || m_interpreter == NULL)
559                    return false;
560
561                return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp);
562            }
563
564            virtual bool
565            MightHaveChildren ()
566            {
567                if (!m_wrapper_sp || m_interpreter == NULL)
568                    return false;
569
570                return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
571            }
572
573            virtual size_t
574            GetIndexOfChildWithName (const ConstString &name)
575            {
576                if (!m_wrapper_sp || m_interpreter == NULL)
577                    return UINT32_MAX;
578                return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString());
579            }
580
581            typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
582
583        private:
584            DISALLOW_COPY_AND_ASSIGN(FrontEnd);
585        };
586
587        virtual SyntheticChildrenFrontEnd::AutoPointer
588        GetFrontEnd(ValueObject &backend)
589        {
590            auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(m_python_class, backend));
591            if (synth_ptr && ((FrontEnd*)synth_ptr.get())->IsValid())
592                return synth_ptr;
593            return NULL;
594        }
595
596    private:
597        DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren);
598    };
599#endif
600} // namespace lldb_private
601
602#endif	// lldb_TypeSynthetic_h_
603