diff options
Diffstat (limited to 'source/Symbol/TypeList.cpp')
-rw-r--r-- | source/Symbol/TypeList.cpp | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/source/Symbol/TypeList.cpp b/source/Symbol/TypeList.cpp new file mode 100644 index 000000000000..a033edd22e1f --- /dev/null +++ b/source/Symbol/TypeList.cpp @@ -0,0 +1,356 @@ +//===-- TypeList.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +// C++ Includes +#include <vector> + +// Other libraries and framework includes +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" + +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" + +// Project includes +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/TypeList.h" + +using namespace lldb; +using namespace lldb_private; +using namespace clang; + +TypeList::TypeList() : + m_types () +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +TypeList::~TypeList() +{ +} + +void +TypeList::Insert (const TypeSP& type_sp) +{ + // Just push each type on the back for now. We will worry about uniquing later + if (type_sp) + m_types.insert(std::make_pair(type_sp->GetID(), type_sp)); +} + + +bool +TypeList::InsertUnique (const TypeSP& type_sp) +{ + if (type_sp) + { + user_id_t type_uid = type_sp->GetID(); + iterator pos, end = m_types.end(); + + for (pos = m_types.find(type_uid); pos != end && pos->second->GetID() == type_uid; ++pos) + { + if (pos->second.get() == type_sp.get()) + return false; + } + } + Insert (type_sp); + return true; +} + +//---------------------------------------------------------------------- +// Find a base type by its unique ID. +//---------------------------------------------------------------------- +//TypeSP +//TypeList::FindType(lldb::user_id_t uid) +//{ +// iterator pos = m_types.find(uid); +// if (pos != m_types.end()) +// return pos->second; +// return TypeSP(); +//} + +//---------------------------------------------------------------------- +// Find a type by name. +//---------------------------------------------------------------------- +//TypeList +//TypeList::FindTypes (const ConstString &name) +//{ +// // Do we ever need to make a lookup by name map? Here we are doing +// // a linear search which isn't going to be fast. +// TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str()); +// iterator pos, end; +// for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) +// if (pos->second->GetName() == name) +// types.Insert (pos->second); +// return types; +//} + +void +TypeList::Clear() +{ + m_types.clear(); +} + +uint32_t +TypeList::GetSize() const +{ + return m_types.size(); +} + +// GetTypeAtIndex isn't used a lot for large type lists, currently only for +// type lists that are returned for "image dump -t TYPENAME" commands and other +// simple symbol queries that grab the first result... + +TypeSP +TypeList::GetTypeAtIndex(uint32_t idx) +{ + iterator pos, end; + uint32_t i = idx; + for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) + { + if (i == 0) + return pos->second; + --i; + } + return TypeSP(); +} + +void +TypeList::ForEach (std::function <bool(const lldb::TypeSP &type_sp)> const &callback) const +{ + for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) + { + if (!callback(pos->second)) + break; + } +} + +void +TypeList::ForEach (std::function <bool(lldb::TypeSP &type_sp)> const &callback) +{ + for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) + { + if (!callback(pos->second)) + break; + } +} + + +bool +TypeList::RemoveTypeWithUID (user_id_t uid) +{ + iterator pos = m_types.find(uid); + + if (pos != m_types.end()) + { + m_types.erase(pos); + return true; + } + return false; +} + + +void +TypeList::Dump(Stream *s, bool show_context) +{ + for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) + { + pos->second->Dump(s, show_context); + } +} + +// depending on implementation details, type lookup might fail because of +// embedded spurious namespace:: prefixes. this call strips them, paying +// attention to the fact that a type might have namespace'd type names as +// arguments to templates, and those must not be stripped off +static bool +GetTypeScopeAndBasename(const char* name_cstr, std::string &scope, std::string &basename, bool *exact_ptr) +{ + // Protect against null c string. + + if (name_cstr && name_cstr[0]) + { + const char *basename_cstr = name_cstr; + const char* namespace_separator = ::strstr (basename_cstr, "::"); + if (namespace_separator) + { + const char* template_arg_char = ::strchr (basename_cstr, '<'); + while (namespace_separator != NULL) + { + if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go + break; + basename_cstr = namespace_separator + 2; + namespace_separator = strstr(basename_cstr, "::"); + } + if (basename_cstr > name_cstr) + { + scope.assign (name_cstr, basename_cstr - name_cstr); + if (scope.size() >= 2 && scope[0] == ':' && scope[1] == ':') + { + // The typename passed in started with "::" so make sure we only do exact matches + if (exact_ptr) + *exact_ptr = true; + // Strip the leading "::" as this won't ever show in qualified typenames we get + // from clang. + scope.erase(0,2); + } + basename.assign (basename_cstr); + return true; + } + } + } + return false; +} + +void +TypeList::RemoveMismatchedTypes (const char *qualified_typename, + bool exact_match) +{ + std::string type_scope; + std::string type_basename; + TypeClass type_class = eTypeClassAny; + if (!Type::GetTypeScopeAndBasename (qualified_typename, type_scope, type_basename, type_class)) + { + type_basename = qualified_typename; + type_scope.clear(); + } + return RemoveMismatchedTypes (type_scope, type_basename, type_class, exact_match); +} + +void +TypeList::RemoveMismatchedTypes (const std::string &type_scope, + const std::string &type_basename, + TypeClass type_class, + bool exact_match) +{ + // Our "collection" type currently is a std::map which doesn't + // have any good way to iterate and remove items from the map + // so we currently just make a new list and add all of the matching + // types to it, and then swap it into m_types at the end + collection matching_types; + + iterator pos, end = m_types.end(); + + for (pos = m_types.begin(); pos != end; ++pos) + { + Type* the_type = pos->second.get(); + bool keep_match = false; + TypeClass match_type_class = eTypeClassAny; + + if (type_class != eTypeClassAny) + { + match_type_class = the_type->GetClangForwardType().GetTypeClass (); + if ((match_type_class & type_class) == 0) + continue; + } + + ConstString match_type_name_const_str (the_type->GetQualifiedName()); + if (match_type_name_const_str) + { + const char *match_type_name = match_type_name_const_str.GetCString(); + std::string match_type_scope; + std::string match_type_basename; + if (Type::GetTypeScopeAndBasename (match_type_name, + match_type_scope, + match_type_basename, + match_type_class)) + { + if (match_type_basename == type_basename) + { + const size_t type_scope_size = type_scope.size(); + const size_t match_type_scope_size = match_type_scope.size(); + if (exact_match || (type_scope_size == match_type_scope_size)) + { + keep_match = match_type_scope == type_scope; + } + else + { + if (match_type_scope_size > type_scope_size) + { + const size_t type_scope_pos = match_type_scope.rfind(type_scope); + if (type_scope_pos == match_type_scope_size - type_scope_size) + { + if (type_scope_pos >= 2) + { + // Our match scope ends with the type scope we were lookikng for, + // but we need to make sure what comes before the matching + // type scope is a namepace boundary in case we are trying to match: + // type_basename = "d" + // type_scope = "b::c::" + // We want to match: + // match_type_scope "a::b::c::" + // But not: + // match_type_scope "a::bb::c::" + // So below we make sure what comes before "b::c::" in match_type_scope + // is "::", or the namespace boundary + if (match_type_scope[type_scope_pos - 1] == ':' && + match_type_scope[type_scope_pos - 2] == ':') + { + keep_match = true; + } + } + } + } + } + } + } + else + { + // The type we are currently looking at doesn't exists + // in a namespace or class, so it only matches if there + // is no type scope... + keep_match = type_scope.empty() && type_basename.compare(match_type_name) == 0; + } + } + + if (keep_match) + { + matching_types.insert (*pos); + } + } + m_types.swap(matching_types); +} + +void +TypeList::RemoveMismatchedTypes (TypeClass type_class) +{ + if (type_class == eTypeClassAny) + return; + + // Our "collection" type currently is a std::map which doesn't + // have any good way to iterate and remove items from the map + // so we currently just make a new list and add all of the matching + // types to it, and then swap it into m_types at the end + collection matching_types; + + iterator pos, end = m_types.end(); + + for (pos = m_types.begin(); pos != end; ++pos) + { + Type* the_type = pos->second.get(); + TypeClass match_type_class = the_type->GetClangForwardType().GetTypeClass (); + if (match_type_class & type_class) + matching_types.insert (*pos); + } + m_types.swap(matching_types); +} |