FormatNavigator.h revision 52f792329be5db8e38961350589e97e8f2823acd
1//===-- FormatNavigator.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_FormatNavigator_h_
11#define lldb_FormatNavigator_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
30#include "lldb/Symbol/ClangASTContext.h"
31#include "lldb/Symbol/ClangASTType.h"
32
33#include "lldb/Target/ObjCLanguageRuntime.h"
34#include "lldb/Target/Process.h"
35#include "lldb/Target/StackFrame.h"
36#include "lldb/Target/TargetList.h"
37
38namespace lldb_private {
39
40// this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization
41// class DataVisualization is the high-level front-end of this feature
42// clients should refer to that class as the entry-point into the data formatters
43// unless they have a good reason to bypass it and prefer to use this file's objects directly
44class IFormatChangeListener
45{
46public:
47    virtual void
48    Changed () = 0;
49
50    virtual
51    ~IFormatChangeListener () {}
52
53    virtual uint32_t
54    GetCurrentRevision () = 0;
55
56};
57
58static inline bool
59IsWhitespace (char c)
60{
61    return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') );
62}
63
64static inline bool
65HasPrefix (const char* str1, const char* str2)
66{
67    return ( ::strstr(str1, str2) == str1 );
68}
69
70// if the user tries to add formatters for, say, "struct Foo"
71// those will not match any type because of the way we strip qualifiers from typenames
72// this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo
73// and strips the unnecessary qualifier
74static inline ConstString
75GetValidTypeName_Impl (const ConstString& type)
76{
77    int strip_len = 0;
78
79    if (type == false)
80        return type;
81
82    const char* type_cstr = type.AsCString();
83
84    if ( HasPrefix(type_cstr, "class ") )
85        strip_len = 6;
86    else if ( HasPrefix(type_cstr, "enum ") )
87        strip_len = 5;
88    else if ( HasPrefix(type_cstr, "struct ") )
89        strip_len = 7;
90    else if ( HasPrefix(type_cstr, "union ") )
91        strip_len = 6;
92
93    if (strip_len == 0)
94        return type;
95
96    type_cstr += strip_len;
97    while (IsWhitespace(*type_cstr) && ++type_cstr)
98        ;
99
100    return ConstString(type_cstr);
101}
102
103template<typename KeyType, typename ValueType>
104class FormatNavigator;
105
106template<typename KeyType, typename ValueType>
107class FormatMap
108{
109public:
110
111    typedef typename ValueType::SharedPointer ValueSP;
112    typedef std::map<KeyType, ValueSP> MapType;
113    typedef typename MapType::iterator MapIterator;
114    typedef bool(*CallbackType)(void*, KeyType, const ValueSP&);
115
116    FormatMap(IFormatChangeListener* lst) :
117    m_map(),
118    m_map_mutex(Mutex::eMutexTypeRecursive),
119    listener(lst)
120    {
121    }
122
123    void
124    Add(KeyType name,
125        const ValueSP& entry)
126    {
127        if (listener)
128            entry->GetRevision() = listener->GetCurrentRevision();
129        else
130            entry->GetRevision() = 0;
131
132        Mutex::Locker locker(m_map_mutex);
133        m_map[name] = entry;
134        if (listener)
135            listener->Changed();
136    }
137
138    bool
139    Delete (KeyType name)
140    {
141        Mutex::Locker locker(m_map_mutex);
142        MapIterator iter = m_map.find(name);
143        if (iter == m_map.end())
144            return false;
145        m_map.erase(name);
146        if (listener)
147            listener->Changed();
148        return true;
149    }
150
151    void
152    Clear ()
153    {
154        Mutex::Locker locker(m_map_mutex);
155        m_map.clear();
156        if (listener)
157            listener->Changed();
158    }
159
160    bool
161    Get(KeyType name,
162        ValueSP& entry)
163    {
164        Mutex::Locker locker(m_map_mutex);
165        MapIterator iter = m_map.find(name);
166        if (iter == m_map.end())
167            return false;
168        entry = iter->second;
169        return true;
170    }
171
172    void
173    LoopThrough (CallbackType callback, void* param)
174    {
175        if (callback)
176        {
177            Mutex::Locker locker(m_map_mutex);
178            MapIterator pos, end = m_map.end();
179            for (pos = m_map.begin(); pos != end; pos++)
180            {
181                KeyType type = pos->first;
182                if (!callback(param, type, pos->second))
183                    break;
184            }
185        }
186    }
187
188    uint32_t
189    GetCount ()
190    {
191        return m_map.size();
192    }
193
194    ValueSP
195    GetValueAtIndex (size_t index)
196    {
197        Mutex::Locker locker(m_map_mutex);
198        MapIterator iter = m_map.begin();
199        MapIterator end = m_map.end();
200        while (index > 0)
201        {
202            iter++;
203            index--;
204            if (end == iter)
205                return ValueSP();
206        }
207        return iter->second;
208    }
209
210    KeyType
211    GetKeyAtIndex (size_t index)
212    {
213        Mutex::Locker locker(m_map_mutex);
214        MapIterator iter = m_map.begin();
215        MapIterator end = m_map.end();
216        while (index > 0)
217        {
218            iter++;
219            index--;
220            if (end == iter)
221                return KeyType();
222        }
223        return iter->first;
224    }
225
226protected:
227    MapType m_map;
228    Mutex m_map_mutex;
229    IFormatChangeListener* listener;
230
231    MapType&
232    map ()
233    {
234        return m_map;
235    }
236
237    Mutex&
238    mutex ()
239    {
240        return m_map_mutex;
241    }
242
243    friend class FormatNavigator<KeyType, ValueType>;
244    friend class FormatManager;
245
246};
247
248template<typename KeyType, typename ValueType>
249class FormatNavigator
250{
251protected:
252    typedef FormatMap<KeyType,ValueType> BackEndType;
253
254public:
255    typedef typename BackEndType::MapType MapType;
256    typedef typename MapType::iterator MapIterator;
257    typedef typename MapType::key_type MapKeyType;
258    typedef typename MapType::mapped_type MapValueType;
259    typedef typename BackEndType::CallbackType CallbackType;
260    typedef typename std::shared_ptr<FormatNavigator<KeyType, ValueType> > SharedPointer;
261
262    friend class TypeCategoryImpl;
263
264    FormatNavigator(std::string name,
265                    IFormatChangeListener* lst) :
266    m_format_map(lst),
267    m_name(name),
268    m_id_cs(ConstString("id"))
269    {
270    }
271
272    void
273    Add (const MapKeyType &type, const MapValueType& entry)
274    {
275        Add_Impl(type, entry, (KeyType*)NULL);
276    }
277
278    bool
279    Delete (ConstString type)
280    {
281        return Delete_Impl(type, (KeyType*)NULL);
282    }
283
284    bool
285    Get(ValueObject& valobj,
286        MapValueType& entry,
287        lldb::DynamicValueType use_dynamic,
288        uint32_t* why = NULL)
289    {
290        uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
291        ClangASTType ast_type(valobj.GetClangType());
292        bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
293        if (ret)
294            entry = MapValueType(entry);
295        else
296            entry = MapValueType();
297        if (why)
298            *why = value;
299        return ret;
300    }
301
302    bool
303    Get (ConstString type, MapValueType& entry)
304    {
305        return Get_Impl(type, entry, (KeyType*)NULL);
306    }
307
308    bool
309    GetExact (ConstString type, MapValueType& entry)
310    {
311        return GetExact_Impl(type, entry, (KeyType*)NULL);
312    }
313
314    MapValueType
315    GetAtIndex (size_t index)
316    {
317        return m_format_map.GetValueAtIndex(index);
318    }
319
320    lldb::TypeNameSpecifierImplSP
321    GetTypeNameSpecifierAtIndex (size_t index)
322    {
323        return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL);
324    }
325
326    void
327    Clear ()
328    {
329        m_format_map.Clear();
330    }
331
332    void
333    LoopThrough (CallbackType callback, void* param)
334    {
335        m_format_map.LoopThrough(callback,param);
336    }
337
338    uint32_t
339    GetCount ()
340    {
341        return m_format_map.GetCount();
342    }
343
344protected:
345
346    BackEndType m_format_map;
347
348    std::string m_name;
349
350    DISALLOW_COPY_AND_ASSIGN(FormatNavigator);
351
352    ConstString m_id_cs;
353
354    void
355    Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy)
356    {
357       m_format_map.Add(type,entry);
358    }
359
360    void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy)
361    {
362       m_format_map.Add(GetValidTypeName_Impl(type), entry);
363    }
364
365    bool
366    Delete_Impl (ConstString type, ConstString *dummy)
367    {
368       return m_format_map.Delete(type);
369    }
370
371    bool
372    Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy)
373    {
374       Mutex& x_mutex = m_format_map.mutex();
375        lldb_private::Mutex::Locker locker(x_mutex);
376       MapIterator pos, end = m_format_map.map().end();
377       for (pos = m_format_map.map().begin(); pos != end; pos++)
378       {
379           lldb::RegularExpressionSP regex = pos->first;
380           if ( ::strcmp(type.AsCString(),regex->GetText()) == 0)
381           {
382               m_format_map.map().erase(pos);
383               if (m_format_map.listener)
384                   m_format_map.listener->Changed();
385               return true;
386           }
387       }
388       return false;
389    }
390
391    bool
392    Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
393    {
394       return m_format_map.Get(type, entry);
395    }
396
397    bool
398    GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
399    {
400        return Get_Impl(type,entry, (KeyType*)0);
401    }
402
403    lldb::TypeNameSpecifierImplSP
404    GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy)
405    {
406        ConstString key = m_format_map.GetKeyAtIndex(index);
407        if (key)
408            return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(),
409                                                                           false));
410        else
411            return lldb::TypeNameSpecifierImplSP();
412    }
413
414    lldb::TypeNameSpecifierImplSP
415    GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy)
416    {
417        lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
418        if (regex.get() == NULL)
419            return lldb::TypeNameSpecifierImplSP();
420        return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(),
421                                                                       true));
422    }
423
424    bool
425    Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
426    {
427       const char* key_cstr = key.AsCString();
428       if (!key_cstr)
429           return false;
430       Mutex& x_mutex = m_format_map.mutex();
431       lldb_private::Mutex::Locker locker(x_mutex);
432       MapIterator pos, end = m_format_map.map().end();
433       for (pos = m_format_map.map().begin(); pos != end; pos++)
434       {
435           lldb::RegularExpressionSP regex = pos->first;
436           if (regex->Execute(key_cstr))
437           {
438               value = pos->second;
439               return true;
440           }
441       }
442       return false;
443    }
444
445    bool
446    GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
447    {
448        Mutex& x_mutex = m_format_map.mutex();
449        lldb_private::Mutex::Locker locker(x_mutex);
450        MapIterator pos, end = m_format_map.map().end();
451        for (pos = m_format_map.map().begin(); pos != end; pos++)
452        {
453            lldb::RegularExpressionSP regex = pos->first;
454            if (strcmp(regex->GetText(),key.AsCString()) == 0)
455            {
456                value = pos->second;
457                return true;
458            }
459        }
460        return false;
461    }
462
463    bool
464    Get_BitfieldMatch (ValueObject& valobj,
465                       ConstString typeName,
466                       MapValueType& entry,
467                       uint32_t& reason)
468    {
469        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
470        // for bitfields, append size to the typename so one can custom format them
471        StreamString sstring;
472        sstring.Printf("%s:%d",typeName.AsCString(),valobj.GetBitfieldBitSize());
473        ConstString bitfieldname = ConstString(sstring.GetData());
474        if (log)
475            log->Printf("[Get_BitfieldMatch] appended bitfield info, final result is %s", bitfieldname.GetCString());
476        if (Get(bitfieldname, entry))
477        {
478            if (log)
479                log->Printf("[Get_BitfieldMatch] bitfield direct match found, returning");
480            return true;
481        }
482        else
483        {
484            reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField;
485            if (log)
486                log->Printf("[Get_BitfieldMatch] no bitfield direct match");
487            return false;
488        }
489    }
490
491    bool Get_ObjC (ValueObject& valobj,
492                   MapValueType& entry)
493    {
494        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
495        lldb::ProcessSP process_sp = valobj.GetProcessSP();
496        ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime();
497        if (runtime == NULL)
498        {
499            if (log)
500                log->Printf("[Get_ObjC] no valid ObjC runtime, skipping dynamic");
501            return false;
502        }
503        ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj));
504        if (!objc_class_sp)
505        {
506            if (log)
507                log->Printf("[Get_ObjC] invalid ISA, skipping dynamic");
508            return false;
509        }
510        ConstString name (objc_class_sp->GetClassName());
511        if (log)
512            log->Printf("[Get_ObjC] dynamic type inferred is %s - looking for direct dynamic match", name.GetCString());
513        if (Get(name, entry))
514        {
515            if (log)
516                log->Printf("[Get_ObjC] direct dynamic match found, returning");
517            return true;
518        }
519        if (log)
520            log->Printf("[Get_ObjC] no dynamic match");
521        return false;
522    }
523
524    bool
525    Get_Impl (ValueObject& valobj,
526              ClangASTType clang_type,
527              MapValueType& entry,
528              lldb::DynamicValueType use_dynamic,
529              uint32_t& reason)
530    {
531        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
532
533        if (!clang_type.IsValid())
534        {
535            if (log)
536                log->Printf("[Get_Impl] type is invalid, returning");
537            return false;
538        }
539
540        clang_type = clang_type.RemoveFastQualifiers();
541
542        ConstString typeName(clang_type.GetConstTypeName());
543
544        if (valobj.GetBitfieldBitSize() > 0)
545        {
546            if (Get_BitfieldMatch(valobj, typeName, entry, reason))
547                return true;
548        }
549
550        if (log)
551            log->Printf("[Get_Impl] trying to get %s for VO name %s of type %s",
552                        m_name.c_str(),
553                        valobj.GetName().AsCString(),
554                        typeName.AsCString());
555
556        if (Get(typeName, entry))
557        {
558            if (log)
559                log->Printf("[Get] direct match found, returning");
560            return true;
561        }
562        if (log)
563            log->Printf("[Get_Impl] no direct match");
564
565        // strip pointers and references and see if that helps
566        if (clang_type.IsReferenceType())
567        {
568            if (log)
569                log->Printf("[Get_Impl] stripping reference");
570            if (Get_Impl(valobj, clang_type.GetNonReferenceType(), entry, use_dynamic, reason) && !entry->SkipsReferences())
571            {
572                reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
573                return true;
574            }
575        }
576        else if (clang_type.IsPointerType())
577        {
578            if (log)
579                log->Printf("[Get_Impl] stripping pointer");
580            if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
581            {
582                reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
583                return true;
584            }
585        }
586
587        bool canBeObjCDynamic = valobj.GetClangType().IsPossibleDynamicType (NULL,
588                                                                             false, // no C++
589                                                                             true); // yes ObjC
590
591        if (canBeObjCDynamic)
592        {
593            if (use_dynamic != lldb::eNoDynamicValues)
594            {
595                if (log)
596                    log->Printf("[Get_Impl] allowed to figure out dynamic ObjC type");
597                if (Get_ObjC(valobj,entry))
598                {
599                    reason |= lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery;
600                    return true;
601                }
602            }
603            if (log)
604                log->Printf("[Get_Impl] dynamic disabled or failed - stripping ObjC pointer");
605            if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
606            {
607                reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
608                return true;
609            }
610        }
611
612        // try to strip typedef chains
613        if (clang_type.IsTypedefType())
614        {
615            if (log)
616                log->Printf("[Get_Impl] stripping typedef");
617            if ((Get_Impl(valobj, clang_type.GetTypedefedType(), entry, use_dynamic, reason)) && entry->Cascades())
618            {
619                reason |= lldb_private::eFormatterChoiceCriterionNavigatedTypedefs;
620                return true;
621            }
622        }
623
624        // out of luck here
625        return false;
626    }
627
628    // we are separately passing in valobj and type because the valobj is fixed (and is used for ObjC discovery and bitfield size)
629    // but the type can change (e.g. stripping pointers, ...)
630    bool Get (ValueObject& valobj,
631              ClangASTType clang_type,
632              MapValueType& entry,
633              lldb::DynamicValueType use_dynamic,
634              uint32_t& reason)
635    {
636        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
637
638        if (Get_Impl (valobj, clang_type, entry, use_dynamic, reason))
639            return true;
640
641        // try going to the unqualified type
642        do {
643            if (log)
644                log->Printf("[Get] trying the unqualified type");
645            if (!clang_type.IsValid())
646                break;
647
648            ClangASTType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType();
649            if (!unqual_clang_ast_type.IsValid())
650            {
651                if (log)
652                    log->Printf("[Get] could not get the unqual_clang_ast_type");
653                break;
654            }
655            if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType())
656            {
657                if (log)
658                    log->Printf("[Get] unqualified type is there and is not the same, let's try");
659                if (Get_Impl (valobj, unqual_clang_ast_type,entry, use_dynamic, reason))
660                    return true;
661            }
662            else if (log)
663                log->Printf("[Get] unqualified type same as original type");
664        } while(false);
665
666        // if all else fails, go to static type
667        if (valobj.IsDynamic())
668        {
669            if (log)
670                log->Printf("[Get] going to static value");
671            lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
672            if (static_value_sp)
673            {
674                if (log)
675                    log->Printf("[Get] has a static value - actually use it");
676                if (Get(*static_value_sp.get(), static_value_sp->GetClangType(), entry, use_dynamic, reason))
677                {
678                    reason |= lldb_private::eFormatterChoiceCriterionWentToStaticValue;
679                    return true;
680                }
681            }
682        }
683
684        return false;
685    }
686};
687
688} // namespace lldb_private
689
690#endif	// lldb_FormatNavigator_h_
691