Home | History | Annotate | Download | only in Symbol
      1 //===-- TypeList.cpp --------------------------------------------*- 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 
     11 // C Includes
     12 // C++ Includes
     13 #include <vector>
     14 
     15 // Other libraries and framework includes
     16 #include "clang/AST/ASTConsumer.h"
     17 #include "clang/AST/ASTContext.h"
     18 #include "clang/AST/Decl.h"
     19 #include "clang/AST/DeclCXX.h"
     20 #include "clang/AST/DeclGroup.h"
     21 
     22 #include "clang/Basic/Builtins.h"
     23 #include "clang/Basic/IdentifierTable.h"
     24 #include "clang/Basic/LangOptions.h"
     25 #include "clang/Basic/SourceManager.h"
     26 #include "clang/Basic/TargetInfo.h"
     27 
     28 #include "llvm/Support/FormattedStream.h"
     29 #include "llvm/Support/raw_ostream.h"
     30 
     31 // Project includes
     32 #include "lldb/Symbol/SymbolFile.h"
     33 #include "lldb/Symbol/SymbolVendor.h"
     34 #include "lldb/Symbol/Type.h"
     35 #include "lldb/Symbol/TypeList.h"
     36 
     37 using namespace lldb;
     38 using namespace lldb_private;
     39 using namespace clang;
     40 
     41 TypeList::TypeList() :
     42     m_types ()
     43 {
     44 }
     45 
     46 //----------------------------------------------------------------------
     47 // Destructor
     48 //----------------------------------------------------------------------
     49 TypeList::~TypeList()
     50 {
     51 }
     52 
     53 void
     54 TypeList::Insert (const TypeSP& type_sp)
     55 {
     56     // Just push each type on the back for now. We will worry about uniquing later
     57     if (type_sp)
     58         m_types.insert(std::make_pair(type_sp->GetID(), type_sp));
     59 }
     60 
     61 
     62 bool
     63 TypeList::InsertUnique (const TypeSP& type_sp)
     64 {
     65     if (type_sp)
     66     {
     67         user_id_t type_uid = type_sp->GetID();
     68         iterator pos, end = m_types.end();
     69 
     70         for (pos = m_types.find(type_uid); pos != end && pos->second->GetID() == type_uid; ++pos)
     71         {
     72             if (pos->second.get() == type_sp.get())
     73                 return false;
     74         }
     75     }
     76     Insert (type_sp);
     77     return true;
     78 }
     79 
     80 //----------------------------------------------------------------------
     81 // Find a base type by its unique ID.
     82 //----------------------------------------------------------------------
     83 //TypeSP
     84 //TypeList::FindType(lldb::user_id_t uid)
     85 //{
     86 //    iterator pos = m_types.find(uid);
     87 //    if (pos != m_types.end())
     88 //        return pos->second;
     89 //    return TypeSP();
     90 //}
     91 
     92 //----------------------------------------------------------------------
     93 // Find a type by name.
     94 //----------------------------------------------------------------------
     95 //TypeList
     96 //TypeList::FindTypes (const ConstString &name)
     97 //{
     98 //    // Do we ever need to make a lookup by name map? Here we are doing
     99 //    // a linear search which isn't going to be fast.
    100 //    TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str());
    101 //    iterator pos, end;
    102 //    for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
    103 //        if (pos->second->GetName() == name)
    104 //            types.Insert (pos->second);
    105 //    return types;
    106 //}
    107 
    108 void
    109 TypeList::Clear()
    110 {
    111     m_types.clear();
    112 }
    113 
    114 uint32_t
    115 TypeList::GetSize() const
    116 {
    117     return m_types.size();
    118 }
    119 
    120 // GetTypeAtIndex isn't used a lot for large type lists, currently only for
    121 // type lists that are returned for "image dump -t TYPENAME" commands and other
    122 // simple symbol queries that grab the first result...
    123 
    124 TypeSP
    125 TypeList::GetTypeAtIndex(uint32_t idx)
    126 {
    127     iterator pos, end;
    128     uint32_t i = idx;
    129     for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
    130     {
    131         if (i == 0)
    132             return pos->second;
    133         --i;
    134     }
    135     return TypeSP();
    136 }
    137 
    138 void
    139 TypeList::ForEach (std::function <bool(const lldb::TypeSP &type_sp)> const &callback) const
    140 {
    141     for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
    142     {
    143         if (!callback(pos->second))
    144             break;
    145     }
    146 }
    147 
    148 void
    149 TypeList::ForEach (std::function <bool(lldb::TypeSP &type_sp)> const &callback)
    150 {
    151     for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
    152     {
    153         if (!callback(pos->second))
    154             break;
    155     }
    156 }
    157 
    158 
    159 bool
    160 TypeList::RemoveTypeWithUID (user_id_t uid)
    161 {
    162     iterator pos = m_types.find(uid);
    163 
    164     if (pos != m_types.end())
    165     {
    166         m_types.erase(pos);
    167         return true;
    168     }
    169     return false;
    170 }
    171 
    172 
    173 void
    174 TypeList::Dump(Stream *s, bool show_context)
    175 {
    176     for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
    177     {
    178         pos->second->Dump(s, show_context);
    179     }
    180 }
    181 
    182 // depending on implementation details, type lookup might fail because of
    183 // embedded spurious namespace:: prefixes. this call strips them, paying
    184 // attention to the fact that a type might have namespace'd type names as
    185 // arguments to templates, and those must not be stripped off
    186 static bool
    187 GetTypeScopeAndBasename(const char* name_cstr, std::string &scope, std::string &basename, bool *exact_ptr)
    188 {
    189     // Protect against null c string.
    190 
    191     if (name_cstr && name_cstr[0])
    192     {
    193         const char *basename_cstr = name_cstr;
    194         const char* namespace_separator = ::strstr (basename_cstr, "::");
    195         if (namespace_separator)
    196         {
    197             const char* template_arg_char = ::strchr (basename_cstr, '<');
    198             while (namespace_separator != NULL)
    199             {
    200                 if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
    201                     break;
    202                 basename_cstr = namespace_separator + 2;
    203                 namespace_separator = strstr(basename_cstr, "::");
    204             }
    205             if (basename_cstr > name_cstr)
    206             {
    207                 scope.assign (name_cstr, basename_cstr - name_cstr);
    208                 if (scope.size() >= 2 && scope[0] == ':' && scope[1] == ':')
    209                 {
    210                     // The typename passed in started with "::" so make sure we only do exact matches
    211                     if (exact_ptr)
    212                         *exact_ptr = true;
    213                     // Strip the leading "::" as this won't ever show in qualified typenames we get
    214                     // from clang.
    215                     scope.erase(0,2);
    216                 }
    217                 basename.assign (basename_cstr);
    218                 return true;
    219             }
    220         }
    221     }
    222     return false;
    223 }
    224 
    225 void
    226 TypeList::RemoveMismatchedTypes (const char *qualified_typename,
    227                                  bool exact_match)
    228 {
    229     std::string type_scope;
    230     std::string type_basename;
    231     TypeClass type_class = eTypeClassAny;
    232     if (!Type::GetTypeScopeAndBasename (qualified_typename, type_scope, type_basename, type_class))
    233     {
    234         type_basename = qualified_typename;
    235         type_scope.clear();
    236     }
    237     return RemoveMismatchedTypes (type_scope, type_basename, type_class, exact_match);
    238 }
    239 
    240 void
    241 TypeList::RemoveMismatchedTypes (const std::string &type_scope,
    242                                  const std::string &type_basename,
    243                                  TypeClass type_class,
    244                                  bool exact_match)
    245 {
    246     // Our "collection" type currently is a std::map which doesn't
    247     // have any good way to iterate and remove items from the map
    248     // so we currently just make a new list and add all of the matching
    249     // types to it, and then swap it into m_types at the end
    250     collection matching_types;
    251 
    252     iterator pos, end = m_types.end();
    253 
    254     for (pos = m_types.begin(); pos != end; ++pos)
    255     {
    256         Type* the_type = pos->second.get();
    257         bool keep_match = false;
    258         TypeClass match_type_class = eTypeClassAny;
    259 
    260         if (type_class != eTypeClassAny)
    261         {
    262             match_type_class = the_type->GetClangForwardType().GetTypeClass ();
    263             if ((match_type_class & type_class) == 0)
    264                 continue;
    265         }
    266 
    267         ConstString match_type_name_const_str (the_type->GetQualifiedName());
    268         if (match_type_name_const_str)
    269         {
    270             const char *match_type_name = match_type_name_const_str.GetCString();
    271             std::string match_type_scope;
    272             std::string match_type_basename;
    273             if (Type::GetTypeScopeAndBasename (match_type_name,
    274                                                match_type_scope,
    275                                                match_type_basename,
    276                                                match_type_class))
    277             {
    278                 if (match_type_basename == type_basename)
    279                 {
    280                     const size_t type_scope_size = type_scope.size();
    281                     const size_t match_type_scope_size = match_type_scope.size();
    282                     if (exact_match || (type_scope_size == match_type_scope_size))
    283                     {
    284                         keep_match = match_type_scope == type_scope;
    285                     }
    286                     else
    287                     {
    288                         if (match_type_scope_size > type_scope_size)
    289                         {
    290                             const size_t type_scope_pos = match_type_scope.rfind(type_scope);
    291                             if (type_scope_pos == match_type_scope_size - type_scope_size)
    292                             {
    293                                 if (type_scope_pos >= 2)
    294                                 {
    295                                     // Our match scope ends with the type scope we were lookikng for,
    296                                     // but we need to make sure what comes before the matching
    297                                     // type scope is a namepace boundary in case we are trying to match:
    298                                     // type_basename = "d"
    299                                     // type_scope = "b::c::"
    300                                     // We want to match:
    301                                     //  match_type_scope "a::b::c::"
    302                                     // But not:
    303                                     //  match_type_scope "a::bb::c::"
    304                                     // So below we make sure what comes before "b::c::" in match_type_scope
    305                                     // is "::", or the namespace boundary
    306                                     if (match_type_scope[type_scope_pos - 1] == ':' &&
    307                                         match_type_scope[type_scope_pos - 2] == ':')
    308                                     {
    309                                         keep_match = true;
    310                                     }
    311                                 }
    312                             }
    313                         }
    314                     }
    315                 }
    316             }
    317             else
    318             {
    319                 // The type we are currently looking at doesn't exists
    320                 // in a namespace or class, so it only matches if there
    321                 // is no type scope...
    322                 keep_match = type_scope.empty() && type_basename.compare(match_type_name) == 0;
    323             }
    324         }
    325 
    326         if (keep_match)
    327         {
    328             matching_types.insert (*pos);
    329         }
    330     }
    331     m_types.swap(matching_types);
    332 }
    333 
    334 void
    335 TypeList::RemoveMismatchedTypes (TypeClass type_class)
    336 {
    337     if (type_class == eTypeClassAny)
    338         return;
    339 
    340     // Our "collection" type currently is a std::map which doesn't
    341     // have any good way to iterate and remove items from the map
    342     // so we currently just make a new list and add all of the matching
    343     // types to it, and then swap it into m_types at the end
    344     collection matching_types;
    345 
    346     iterator pos, end = m_types.end();
    347 
    348     for (pos = m_types.begin(); pos != end; ++pos)
    349     {
    350         Type* the_type = pos->second.get();
    351         TypeClass match_type_class = the_type->GetClangForwardType().GetTypeClass ();
    352         if (match_type_class & type_class)
    353             matching_types.insert (*pos);
    354     }
    355     m_types.swap(matching_types);
    356 }
    357