FormattersContainer.h revision 269024
1//===-- FormattersContainer.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_FormattersContainer_h_
11#define lldb_FormattersContainer_h_
12
13// C Includes
14// C++ Includes
15
16// Other libraries and framework includes
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Type.h"
19#include "clang/AST/DeclObjC.h"
20
21// Project includes
22#include "lldb/lldb-public.h"
23
24#include "lldb/Core/Log.h"
25#include "lldb/Core/RegularExpression.h"
26#include "lldb/Core/ValueObject.h"
27
28#include "lldb/DataFormatters/FormatClasses.h"
29#include "lldb/DataFormatters/TypeFormat.h"
30#include "lldb/DataFormatters/TypeSummary.h"
31#include "lldb/DataFormatters/TypeSynthetic.h"
32
33#include "lldb/Symbol/ClangASTContext.h"
34#include "lldb/Symbol/ClangASTType.h"
35
36#include "lldb/Target/ObjCLanguageRuntime.h"
37#include "lldb/Target/Process.h"
38#include "lldb/Target/StackFrame.h"
39#include "lldb/Target/TargetList.h"
40
41namespace lldb_private {
42
43// this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization
44// class DataVisualization is the high-level front-end of this feature
45// clients should refer to that class as the entry-point into the data formatters
46// unless they have a good reason to bypass it and prefer to use this file's objects directly
47class IFormatChangeListener
48{
49public:
50    virtual void
51    Changed () = 0;
52
53    virtual
54    ~IFormatChangeListener () {}
55
56    virtual uint32_t
57    GetCurrentRevision () = 0;
58
59};
60
61static inline bool
62IsWhitespace (char c)
63{
64    return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') );
65}
66
67static inline bool
68HasPrefix (const char* str1, const char* str2)
69{
70    return ( ::strstr(str1, str2) == str1 );
71}
72
73// if the user tries to add formatters for, say, "struct Foo"
74// those will not match any type because of the way we strip qualifiers from typenames
75// this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo
76// and strips the unnecessary qualifier
77static inline ConstString
78GetValidTypeName_Impl (const ConstString& type)
79{
80    int strip_len = 0;
81
82    if ((bool)type == false)
83        return type;
84
85    const char* type_cstr = type.AsCString();
86
87    if ( HasPrefix(type_cstr, "class ") )
88        strip_len = 6;
89    else if ( HasPrefix(type_cstr, "enum ") )
90        strip_len = 5;
91    else if ( HasPrefix(type_cstr, "struct ") )
92        strip_len = 7;
93    else if ( HasPrefix(type_cstr, "union ") )
94        strip_len = 6;
95
96    if (strip_len == 0)
97        return type;
98
99    type_cstr += strip_len;
100    while (IsWhitespace(*type_cstr) && ++type_cstr)
101        ;
102
103    return ConstString(type_cstr);
104}
105
106template<typename KeyType, typename ValueType>
107class FormattersContainer;
108
109template<typename KeyType, typename ValueType>
110class FormatMap
111{
112public:
113
114    typedef typename ValueType::SharedPointer ValueSP;
115    typedef std::map<KeyType, ValueSP> MapType;
116    typedef typename MapType::iterator MapIterator;
117    typedef bool(*CallbackType)(void*, KeyType, const ValueSP&);
118
119    FormatMap(IFormatChangeListener* lst) :
120    m_map(),
121    m_map_mutex(Mutex::eMutexTypeRecursive),
122    listener(lst)
123    {
124    }
125
126    void
127    Add(KeyType name,
128        const ValueSP& entry)
129    {
130        if (listener)
131            entry->GetRevision() = listener->GetCurrentRevision();
132        else
133            entry->GetRevision() = 0;
134
135        Mutex::Locker locker(m_map_mutex);
136        m_map[name] = entry;
137        if (listener)
138            listener->Changed();
139    }
140
141    bool
142    Delete (KeyType name)
143    {
144        Mutex::Locker locker(m_map_mutex);
145        MapIterator iter = m_map.find(name);
146        if (iter == m_map.end())
147            return false;
148        m_map.erase(name);
149        if (listener)
150            listener->Changed();
151        return true;
152    }
153
154    void
155    Clear ()
156    {
157        Mutex::Locker locker(m_map_mutex);
158        m_map.clear();
159        if (listener)
160            listener->Changed();
161    }
162
163    bool
164    Get(KeyType name,
165        ValueSP& entry)
166    {
167        Mutex::Locker locker(m_map_mutex);
168        MapIterator iter = m_map.find(name);
169        if (iter == m_map.end())
170            return false;
171        entry = iter->second;
172        return true;
173    }
174
175    void
176    LoopThrough (CallbackType callback, void* param)
177    {
178        if (callback)
179        {
180            Mutex::Locker locker(m_map_mutex);
181            MapIterator pos, end = m_map.end();
182            for (pos = m_map.begin(); pos != end; pos++)
183            {
184                KeyType type = pos->first;
185                if (!callback(param, type, pos->second))
186                    break;
187            }
188        }
189    }
190
191    uint32_t
192    GetCount ()
193    {
194        return m_map.size();
195    }
196
197    ValueSP
198    GetValueAtIndex (size_t index)
199    {
200        Mutex::Locker locker(m_map_mutex);
201        MapIterator iter = m_map.begin();
202        MapIterator end = m_map.end();
203        while (index > 0)
204        {
205            iter++;
206            index--;
207            if (end == iter)
208                return ValueSP();
209        }
210        return iter->second;
211    }
212
213    KeyType
214    GetKeyAtIndex (size_t index)
215    {
216        Mutex::Locker locker(m_map_mutex);
217        MapIterator iter = m_map.begin();
218        MapIterator end = m_map.end();
219        while (index > 0)
220        {
221            iter++;
222            index--;
223            if (end == iter)
224                return KeyType();
225        }
226        return iter->first;
227    }
228
229protected:
230    MapType m_map;
231    Mutex m_map_mutex;
232    IFormatChangeListener* listener;
233
234    MapType&
235    map ()
236    {
237        return m_map;
238    }
239
240    Mutex&
241    mutex ()
242    {
243        return m_map_mutex;
244    }
245
246    friend class FormattersContainer<KeyType, ValueType>;
247    friend class FormatManager;
248
249};
250
251template<typename KeyType, typename ValueType>
252class FormattersContainer
253{
254protected:
255    typedef FormatMap<KeyType,ValueType> BackEndType;
256
257public:
258    typedef typename BackEndType::MapType MapType;
259    typedef typename MapType::iterator MapIterator;
260    typedef typename MapType::key_type MapKeyType;
261    typedef typename MapType::mapped_type MapValueType;
262    typedef typename BackEndType::CallbackType CallbackType;
263    typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType> > SharedPointer;
264
265    friend class TypeCategoryImpl;
266
267    FormattersContainer(std::string name,
268                    IFormatChangeListener* lst) :
269    m_format_map(lst),
270    m_name(name),
271    m_id_cs(ConstString("id"))
272    {
273    }
274
275    void
276    Add (const MapKeyType &type, const MapValueType& entry)
277    {
278        Add_Impl(type, entry, (KeyType*)NULL);
279    }
280
281    bool
282    Delete (ConstString type)
283    {
284        return Delete_Impl(type, (KeyType*)NULL);
285    }
286
287    bool
288    Get(ValueObject& valobj,
289        MapValueType& entry,
290        lldb::DynamicValueType use_dynamic,
291        uint32_t* why = NULL)
292    {
293        uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
294        ClangASTType ast_type(valobj.GetClangType());
295        bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
296        if (ret)
297            entry = MapValueType(entry);
298        else
299            entry = MapValueType();
300        if (why)
301            *why = value;
302        return ret;
303    }
304
305    bool
306    Get (ConstString type, MapValueType& entry)
307    {
308        return Get_Impl(type, entry, (KeyType*)NULL);
309    }
310
311    bool
312    GetExact (ConstString type, MapValueType& entry)
313    {
314        return GetExact_Impl(type, entry, (KeyType*)NULL);
315    }
316
317    MapValueType
318    GetAtIndex (size_t index)
319    {
320        return m_format_map.GetValueAtIndex(index);
321    }
322
323    lldb::TypeNameSpecifierImplSP
324    GetTypeNameSpecifierAtIndex (size_t index)
325    {
326        return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL);
327    }
328
329    void
330    Clear ()
331    {
332        m_format_map.Clear();
333    }
334
335    void
336    LoopThrough (CallbackType callback, void* param)
337    {
338        m_format_map.LoopThrough(callback,param);
339    }
340
341    uint32_t
342    GetCount ()
343    {
344        return m_format_map.GetCount();
345    }
346
347protected:
348
349    BackEndType m_format_map;
350
351    std::string m_name;
352
353    DISALLOW_COPY_AND_ASSIGN(FormattersContainer);
354
355    ConstString m_id_cs;
356
357    void
358    Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy)
359    {
360       m_format_map.Add(type,entry);
361    }
362
363    void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy)
364    {
365       m_format_map.Add(GetValidTypeName_Impl(type), entry);
366    }
367
368    bool
369    Delete_Impl (ConstString type, ConstString *dummy)
370    {
371       return m_format_map.Delete(type);
372    }
373
374    bool
375    Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy)
376    {
377       Mutex& x_mutex = m_format_map.mutex();
378        lldb_private::Mutex::Locker locker(x_mutex);
379       MapIterator pos, end = m_format_map.map().end();
380       for (pos = m_format_map.map().begin(); pos != end; pos++)
381       {
382           lldb::RegularExpressionSP regex = pos->first;
383           if ( ::strcmp(type.AsCString(),regex->GetText()) == 0)
384           {
385               m_format_map.map().erase(pos);
386               if (m_format_map.listener)
387                   m_format_map.listener->Changed();
388               return true;
389           }
390       }
391       return false;
392    }
393
394    bool
395    Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
396    {
397       return m_format_map.Get(type, entry);
398    }
399
400    bool
401    GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
402    {
403        return Get_Impl(type,entry, (KeyType*)0);
404    }
405
406    lldb::TypeNameSpecifierImplSP
407    GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy)
408    {
409        ConstString key = m_format_map.GetKeyAtIndex(index);
410        if (key)
411            return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(),
412                                                                           false));
413        else
414            return lldb::TypeNameSpecifierImplSP();
415    }
416
417    lldb::TypeNameSpecifierImplSP
418    GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy)
419    {
420        lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
421        if (regex.get() == NULL)
422            return lldb::TypeNameSpecifierImplSP();
423        return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(),
424                                                                       true));
425    }
426
427    bool
428    Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
429    {
430       const char* key_cstr = key.AsCString();
431       if (!key_cstr)
432           return false;
433       Mutex& x_mutex = m_format_map.mutex();
434       lldb_private::Mutex::Locker locker(x_mutex);
435       MapIterator pos, end = m_format_map.map().end();
436       for (pos = m_format_map.map().begin(); pos != end; pos++)
437       {
438           lldb::RegularExpressionSP regex = pos->first;
439           if (regex->Execute(key_cstr))
440           {
441               value = pos->second;
442               return true;
443           }
444       }
445       return false;
446    }
447
448    bool
449    GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
450    {
451        Mutex& x_mutex = m_format_map.mutex();
452        lldb_private::Mutex::Locker locker(x_mutex);
453        MapIterator pos, end = m_format_map.map().end();
454        for (pos = m_format_map.map().begin(); pos != end; pos++)
455        {
456            lldb::RegularExpressionSP regex = pos->first;
457            if (strcmp(regex->GetText(),key.AsCString()) == 0)
458            {
459                value = pos->second;
460                return true;
461            }
462        }
463        return false;
464    }
465
466    bool
467    Get (const FormattersMatchVector& candidates,
468         MapValueType& entry,
469         uint32_t *reason)
470    {
471        for (const FormattersMatchCandidate& candidate : candidates)
472        {
473            // FIXME: could we do the IsMatch() check first?
474            if (Get(candidate.GetTypeName(),entry))
475            {
476                if (candidate.IsMatch(entry) == false)
477                {
478                    entry.reset();
479                    continue;
480                }
481                else
482                {
483                    if(reason)
484                        *reason = candidate.GetReason();
485                    return true;
486                }
487            }
488        }
489        return false;
490    }
491};
492
493} // namespace lldb_private
494
495#endif	// lldb_FormattersContainer_h_
496