Home | History | Annotate | Download | only in Target
      1 //===-- CPPLanguageRuntime.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 #include "lldb/Target/CPPLanguageRuntime.h"
     11 
     12 #include <string.h>
     13 
     14 #include "lldb/Core/PluginManager.h"
     15 #include "lldb/Core/UniqueCStringMap.h"
     16 #include "lldb/Target/ExecutionContext.h"
     17 
     18 using namespace lldb;
     19 using namespace lldb_private;
     20 
     21 class CPPRuntimeEquivalents
     22 {
     23 public:
     24     CPPRuntimeEquivalents ()
     25     {
     26 
     27         m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("basic_string<char>"));
     28 
     29         // these two (with a prefixed std::) occur when c++stdlib string class occurs as a template argument in some STL container
     30         m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("std::basic_string<char>"));
     31 
     32         m_impl.Sort();
     33     }
     34 
     35     void
     36     Add (ConstString& type_name,
     37          ConstString& type_equivalent)
     38     {
     39         m_impl.Insert(type_name.AsCString(), type_equivalent);
     40     }
     41 
     42     uint32_t
     43     FindExactMatches (ConstString& type_name,
     44                       std::vector<ConstString>& equivalents)
     45     {
     46 
     47         uint32_t count = 0;
     48 
     49         for (ImplData match = m_impl.FindFirstValueForName(type_name.AsCString());
     50              match != NULL;
     51              match = m_impl.FindNextValueForName(match))
     52         {
     53             equivalents.push_back(match->value);
     54             count++;
     55         }
     56 
     57         return count;
     58     }
     59 
     60     // partial matches can occur when a name with equivalents is a template argument.
     61     // e.g. we may have "class Foo" be a match for "struct Bar". if we have a typename
     62     // such as "class Templatized<class Foo, Anything>" we want this to be replaced with
     63     // "class Templatized<struct Bar, Anything>". Since partial matching is time consuming
     64     // once we get a partial match, we add it to the exact matches list for faster retrieval
     65     uint32_t
     66     FindPartialMatches (ConstString& type_name,
     67                         std::vector<ConstString>& equivalents)
     68     {
     69 
     70         uint32_t count = 0;
     71 
     72         const char* type_name_cstr = type_name.AsCString();
     73 
     74         size_t items_count = m_impl.GetSize();
     75 
     76         for (size_t item = 0; item < items_count; item++)
     77         {
     78             const char* key_cstr = m_impl.GetCStringAtIndex(item);
     79             if ( strstr(type_name_cstr,key_cstr) )
     80             {
     81                 count += AppendReplacements(type_name_cstr,
     82                                             key_cstr,
     83                                             equivalents);
     84             }
     85         }
     86 
     87         return count;
     88 
     89     }
     90 
     91 private:
     92 
     93     std::string& replace (std::string& target,
     94                           std::string& pattern,
     95                           std::string& with)
     96     {
     97         size_t pos;
     98         size_t pattern_len = pattern.size();
     99 
    100         while ( (pos = target.find(pattern)) != std::string::npos )
    101             target.replace(pos, pattern_len, with);
    102 
    103         return target;
    104     }
    105 
    106     uint32_t
    107     AppendReplacements (const char* original,
    108                         const char *matching_key,
    109                         std::vector<ConstString>& equivalents)
    110     {
    111 
    112         std::string matching_key_str(matching_key);
    113         ConstString original_const(original);
    114 
    115         uint32_t count = 0;
    116 
    117         for (ImplData match = m_impl.FindFirstValueForName(matching_key);
    118              match != NULL;
    119              match = m_impl.FindNextValueForName(match))
    120         {
    121             std::string target(original);
    122             std::string equiv_class(match->value.AsCString());
    123 
    124             replace (target, matching_key_str, equiv_class);
    125 
    126             ConstString target_const(target.c_str());
    127 
    128 // you will most probably want to leave this off since it might make this map grow indefinitely
    129 #ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW
    130             Add(original_const, target_const);
    131 #endif
    132             equivalents.push_back(target_const);
    133 
    134             count++;
    135         }
    136 
    137         return count;
    138     }
    139 
    140     typedef UniqueCStringMap<ConstString> Impl;
    141     typedef const Impl::Entry* ImplData;
    142     Impl m_impl;
    143 };
    144 
    145 static CPPRuntimeEquivalents&
    146 GetEquivalentsMap ()
    147 {
    148     static CPPRuntimeEquivalents g_equivalents_map;
    149     return g_equivalents_map;
    150 }
    151 
    152 //----------------------------------------------------------------------
    153 // Destructor
    154 //----------------------------------------------------------------------
    155 CPPLanguageRuntime::~CPPLanguageRuntime()
    156 {
    157 }
    158 
    159 CPPLanguageRuntime::CPPLanguageRuntime (Process *process) :
    160     LanguageRuntime (process)
    161 {
    162 
    163 }
    164 
    165 bool
    166 CPPLanguageRuntime::GetObjectDescription (Stream &str, ValueObject &object)
    167 {
    168     // C++ has no generic way to do this.
    169     return false;
    170 }
    171 
    172 bool
    173 CPPLanguageRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope)
    174 {
    175     // C++ has no generic way to do this.
    176     return false;
    177 }
    178 
    179 bool
    180 CPPLanguageRuntime::IsCPPMangledName (const char *name)
    181 {
    182     // FIXME, we should really run through all the known C++ Language plugins and ask each one if
    183     // this is a C++ mangled name, but we can put that off till there is actually more than one
    184     // we care about.
    185 
    186     if (name && name[0] == '_' && name[1] == 'Z')
    187         return true;
    188     else
    189         return false;
    190 }
    191 
    192 bool
    193 CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end)
    194 {
    195     if (base_name_end == NULL)
    196         base_name_end = name + strlen (name);
    197 
    198     const char *last_colon = strrchr (name, ':');
    199 
    200     if (last_colon == NULL)
    201     {
    202         base_name_start = name;
    203         return true;
    204     }
    205 
    206     // Can't have a C++ name that begins with a single ':', nor contains an internal single ':'
    207     if (last_colon == name)
    208         return false;
    209     else if (last_colon[-1] != ':')
    210         return false;
    211     else
    212     {
    213         // FIXME: should check if there is
    214         base_name_start = last_colon + 1;
    215         return true;
    216     }
    217 }
    218 
    219 uint32_t
    220 CPPLanguageRuntime::FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents)
    221 {
    222     uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents);
    223 
    224     bool might_have_partials=
    225         ( count == 0 )  // if we have a full name match just use it
    226         && (strchr(type_name.AsCString(), '<') != NULL  // we should only have partial matches when templates are involved, check that we have
    227             && strchr(type_name.AsCString(), '>') != NULL); // angle brackets in the type_name before trying to scan for partial matches
    228 
    229     if ( might_have_partials )
    230         count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents);
    231 
    232     return count;
    233 }
    234 
    235 void
    236 CPPLanguageRuntime::MethodName::Clear()
    237 {
    238     m_full.Clear();
    239     m_basename = llvm::StringRef();
    240     m_context = llvm::StringRef();
    241     m_arguments = llvm::StringRef();
    242     m_qualifiers = llvm::StringRef();
    243     m_type = eTypeInvalid;
    244     m_parsed = false;
    245     m_parse_error = false;
    246 }
    247 
    248 bool
    249 ReverseFindMatchingChars (const llvm::StringRef &s,
    250                           const llvm::StringRef &left_right_chars,
    251                           size_t &left_pos,
    252                           size_t &right_pos,
    253                           size_t pos = llvm::StringRef::npos)
    254 {
    255     assert (left_right_chars.size() == 2);
    256     left_pos = llvm::StringRef::npos;
    257     const char left_char = left_right_chars[0];
    258     const char right_char = left_right_chars[1];
    259     pos = s.find_last_of(left_right_chars, pos);
    260     if (pos == llvm::StringRef::npos || s[pos] == left_char)
    261         return false;
    262     right_pos = pos;
    263     uint32_t depth = 1;
    264     while (pos > 0 && depth > 0)
    265     {
    266         pos = s.find_last_of(left_right_chars, pos);
    267         if (pos == llvm::StringRef::npos)
    268             return false;
    269         if (s[pos] == left_char)
    270         {
    271             if (--depth == 0)
    272             {
    273                 left_pos = pos;
    274                 return left_pos < right_pos;
    275             }
    276         }
    277         else if (s[pos] == right_char)
    278         {
    279             ++depth;
    280         }
    281     }
    282     return false;
    283 }
    284 
    285 void
    286 CPPLanguageRuntime::MethodName::Parse()
    287 {
    288     if (!m_parsed && m_full)
    289     {
    290 //        ConstString mangled;
    291 //        m_full.GetMangledCounterpart(mangled);
    292 //        printf ("\n   parsing = '%s'\n", m_full.GetCString());
    293 //        if (mangled)
    294 //            printf ("   mangled = '%s'\n", mangled.GetCString());
    295         m_parse_error = false;
    296         m_parsed = true;
    297         llvm::StringRef full (m_full.GetCString());
    298 
    299         size_t arg_start, arg_end;
    300         llvm::StringRef parens("()", 2);
    301         if (ReverseFindMatchingChars (full, parens, arg_start, arg_end))
    302         {
    303             m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
    304             if (arg_end + 1 < full.size())
    305                 m_qualifiers = full.substr(arg_end + 1);
    306             if (arg_start > 0)
    307             {
    308                 size_t basename_end = arg_start;
    309                 size_t context_end = llvm::StringRef::npos;
    310                 if (basename_end > 0 && full[basename_end-1] == '>')
    311                 {
    312                     // TODO: handle template junk...
    313                     // Templated function
    314                     size_t template_start, template_end;
    315                     llvm::StringRef lt_gt("<>", 2);
    316                     if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end))
    317                         context_end = full.rfind(':', template_start);
    318                 }
    319                 if (context_end == llvm::StringRef::npos)
    320                     context_end = full.rfind(':', basename_end);
    321 
    322                 if (context_end == llvm::StringRef::npos)
    323                     m_basename = full.substr(0, basename_end);
    324                 else
    325                 {
    326                     m_context = full.substr(0, context_end - 1);
    327                     const size_t basename_begin = context_end + 1;
    328                     m_basename = full.substr(basename_begin, basename_end - basename_begin);
    329                 }
    330                 m_type = eTypeUnknownMethod;
    331             }
    332             else
    333             {
    334                 m_parse_error = true;
    335                 return;
    336             }
    337 
    338 //            if (!m_context.empty())
    339 //                printf ("   context = '%s'\n", m_context.str().c_str());
    340 //            if (m_basename)
    341 //                printf ("  basename = '%s'\n", m_basename.GetCString());
    342 //            if (!m_arguments.empty())
    343 //                printf (" arguments = '%s'\n", m_arguments.str().c_str());
    344 //            if (!m_qualifiers.empty())
    345 //                printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str());
    346         }
    347         else
    348         {
    349             m_parse_error = true;
    350 //            printf ("error: didn't find matching parens for arguments\n");
    351         }
    352     }
    353 }
    354 
    355 llvm::StringRef
    356 CPPLanguageRuntime::MethodName::GetBasename ()
    357 {
    358     if (!m_parsed)
    359         Parse();
    360     return m_basename;
    361 }
    362 
    363 llvm::StringRef
    364 CPPLanguageRuntime::MethodName::GetContext ()
    365 {
    366     if (!m_parsed)
    367         Parse();
    368     return m_context;
    369 }
    370 
    371 llvm::StringRef
    372 CPPLanguageRuntime::MethodName::GetArguments ()
    373 {
    374     if (!m_parsed)
    375         Parse();
    376     return m_arguments;
    377 }
    378 
    379 llvm::StringRef
    380 CPPLanguageRuntime::MethodName::GetQualifiers ()
    381 {
    382     if (!m_parsed)
    383         Parse();
    384     return m_qualifiers;
    385 }
    386 
    387