Author: enrico Date: Thu Oct 1 13:16:18 2015 New Revision: 249047 URL: http://llvm.org/viewvc/llvm-project?rev=249047&view=rev Log: Add a 'type lookup' command. This command is meant to look up type information by name in a language-specific way.
Currently, it only supports Objective-C - C++ types can be looked up through debug info via 'image lookup -t', whereas ObjC types via this command are looked up by runtime introspection This behavior is in line with type lookup's behavior in Xcode 7, but I am definitely open to feedback as to what makes the most sense here Modified: lldb/trunk/include/lldb/Target/Language.h lldb/trunk/source/Commands/CommandObjectType.cpp lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h lldb/trunk/source/Target/Language.cpp Modified: lldb/trunk/include/lldb/Target/Language.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Language.h?rev=249047&r1=249046&r2=249047&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Language.h (original) +++ lldb/trunk/include/lldb/Target/Language.h Thu Oct 1 13:16:18 2015 @@ -13,6 +13,8 @@ // C Includes // C++ Includes #include <functional> +#include <memory> +#include <set> #include <vector> // Other libraries and framework includes @@ -29,6 +31,42 @@ class Language : public PluginInterface { public: + + class TypeScavenger + { + public: + class Result + { + public: + virtual bool + IsValid () = 0; + + virtual bool + DumpToStream (Stream& stream, + bool print_help_if_available) = 0; + + virtual ~Result() = default; + }; + + typedef std::set<std::unique_ptr<Result>> ResultSet; + + virtual ~TypeScavenger () = default; + + size_t + Find (ExecutionContextScope *exe_scope, + const char *key, + ResultSet &results, + bool append = true); + + protected: + TypeScavenger () = default; + + virtual bool + Find_Impl (ExecutionContextScope *exe_scope, + const char *key, + ResultSet &results) = 0; + }; + ~Language() override; static Language* @@ -65,6 +103,9 @@ public: virtual lldb_private::formatters::StringPrinter::EscapingHelper GetStringPrinterEscapingHelper (lldb_private::formatters::StringPrinter::GetPrintableElementType); + virtual std::unique_ptr<TypeScavenger> + GetTypeScavenger (); + // These are accessors for general information about the Languages lldb knows about: static lldb::LanguageType @@ -91,7 +132,6 @@ public: static bool LanguageIsPascal (lldb::LanguageType language); - protected: //------------------------------------------------------------------ Modified: lldb/trunk/source/Commands/CommandObjectType.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectType.cpp?rev=249047&r1=249046&r2=249047&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectType.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectType.cpp Thu Oct 1 13:16:18 2015 @@ -4558,6 +4558,218 @@ CommandObjectTypeFilterAdd::CommandOptio { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; +//---------------------------------------------------------------------- +// "type lookup" +//---------------------------------------------------------------------- +class CommandObjectTypeLookup : public CommandObjectRaw +{ +protected: + + class CommandOptions : public OptionGroup + { + public: + + CommandOptions () : + OptionGroup(), + m_show_help(false), + m_language(eLanguageTypeUnknown) + {} + + virtual + ~CommandOptions () {} + + virtual uint32_t + GetNumDefinitions () + { + return 3; + } + + virtual const OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + virtual Error + SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_value) + { + Error error; + + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) + { + case 'h': + m_show_help = true; + break; + + case 'l': + m_language = Language::GetLanguageTypeFromString(option_value); + break; + + default: + error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); + break; + } + + return error; + } + + virtual void + OptionParsingStarting (CommandInterpreter &interpreter) + { + m_show_help = false; + m_language = eLanguageTypeUnknown; + } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + bool m_show_help; + lldb::LanguageType m_language; + }; + + OptionGroupOptions m_option_group; + CommandOptions m_command_options; + +public: + + CommandObjectTypeLookup (CommandInterpreter &interpreter) : + CommandObjectRaw (interpreter, + "type lookup", + "Lookup a type by name in the select target.", + "type lookup <typename>", + eCommandRequiresTarget), + m_option_group(interpreter), + m_command_options() + { + m_option_group.Append(&m_command_options); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectTypeLookup () + { + } + + virtual + Options * + GetOptions () + { + return &m_option_group; + } + + virtual bool + DoExecute (const char *raw_command_line, CommandReturnObject &result) + { + if (!raw_command_line || !raw_command_line[0]) + { + result.SetError("type lookup cannot be invoked without a type name as argument"); + return false; + } + + m_option_group.NotifyOptionParsingStarting(); + + const char * name_of_type = NULL; + + if (raw_command_line[0] == '-') + { + // We have some options and these options MUST end with --. + const char *end_options = NULL; + const char *s = raw_command_line; + while (s && s[0]) + { + end_options = ::strstr (s, "--"); + if (end_options) + { + end_options += 2; // Get past the "--" + if (::isspace (end_options[0])) + { + name_of_type = end_options; + while (::isspace (*name_of_type)) + ++name_of_type; + break; + } + } + s = end_options; + } + + if (end_options) + { + Args args (llvm::StringRef(raw_command_line, end_options - raw_command_line)); + if (!ParseOptions (args, result)) + return false; + + Error error (m_option_group.NotifyOptionParsingFinished()); + if (error.Fail()) + { + result.AppendError (error.AsCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + } + if (nullptr == name_of_type) + name_of_type = raw_command_line; + + TargetSP target_sp(GetCommandInterpreter().GetDebugger().GetSelectedTarget()); + const bool fill_all_in = true; + ExecutionContext exe_ctx(target_sp.get(), fill_all_in); + ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope(); + + bool any_found = false; + + std::vector<Language*> languages; + + if (m_command_options.m_language == eLanguageTypeUnknown) + { + // FIXME: hardcoding languages is not good + languages.push_back(Language::FindPlugin(eLanguageTypeObjC)); + languages.push_back(Language::FindPlugin(eLanguageTypeC_plus_plus)); + } + else + { + languages.push_back(Language::FindPlugin(m_command_options.m_language)); + } + + for (Language* language : languages) + { + if (!language) + continue; + + if (auto scavenger = language->GetTypeScavenger()) + { + Language::TypeScavenger::ResultSet search_results; + if (scavenger->Find(best_scope, name_of_type, search_results) > 0) + { + for (const auto& search_result : search_results) + { + if (search_result && search_result->IsValid()) + { + any_found = true; + search_result->DumpToStream(result.GetOutputStream(), this->m_command_options.m_show_help); + } + } + } + } + } + + result.SetStatus (any_found ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult); + return true; + } + +}; + +OptionDefinition +CommandObjectTypeLookup::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_ALL, false, "show-help", 'h', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display available help for types"}, + { LLDB_OPT_SET_ALL, false, "language", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage, "Which language's types should the search scope be"}, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + template <typename FormatterType> class CommandObjectFormatterInfo : public CommandObjectRaw { @@ -4778,6 +4990,7 @@ CommandObjectType::CommandObjectType (Co #ifndef LLDB_DISABLE_PYTHON LoadSubCommand ("synthetic", CommandObjectSP (new CommandObjectTypeSynth (interpreter))); #endif + LoadSubCommand ("lookup", CommandObjectSP (new CommandObjectTypeLookup (interpreter))); } Modified: lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp?rev=249047&r1=249046&r2=249047&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp (original) +++ lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.cpp Thu Oct 1 13:16:18 2015 @@ -656,3 +656,91 @@ ObjCLanguage::GetPossibleFormattersMatch return result; } + +std::unique_ptr<Language::TypeScavenger> +ObjCLanguage::GetTypeScavenger () +{ + class ObjCTypeScavenger : public Language::TypeScavenger + { + private: + class ObjCScavengerResult : public Language::TypeScavenger::Result + { + public: + ObjCScavengerResult (CompilerType type) : + Language::TypeScavenger::Result(), + m_compiler_type(type) + { + } + + bool + IsValid () override + { + return m_compiler_type.IsValid(); + } + + bool + DumpToStream (Stream& stream, + bool print_help_if_available) override + { + if (IsValid()) + { + m_compiler_type.DumpTypeDescription(&stream); + stream.EOL(); + return true; + } + return false; + } + + virtual ~ObjCScavengerResult() = default; + private: + CompilerType m_compiler_type; + }; + + protected: + ObjCTypeScavenger() = default; + + virtual ~ObjCTypeScavenger() = default; + + bool + Find_Impl (ExecutionContextScope *exe_scope, + const char *key, + ResultSet &results) override + { + bool result = false; + + Process* process = exe_scope->CalculateProcess().get(); + if (process) + { + const bool create_on_demand = false; + auto objc_runtime = process->GetObjCLanguageRuntime(create_on_demand); + if (objc_runtime) + { + auto decl_vendor = objc_runtime->GetDeclVendor(); + if (decl_vendor) + { + std::vector<clang::NamedDecl *> decls; + ConstString name(key); + decl_vendor->FindDecls(name, true, UINT32_MAX, decls); + for (auto decl : decls) + { + if (decl) + { + if (CompilerType candidate = ClangASTContext::GetTypeForDecl(decl)) + { + result = true; + std::unique_ptr<Language::TypeScavenger::Result> result(new ObjCScavengerResult(candidate)); + results.insert(std::move(result)); + } + } + } + } + } + } + return result; + } + + friend class ObjCLanguage; + }; + + return std::unique_ptr<TypeScavenger>(new ObjCTypeScavenger()); +} Modified: lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h?rev=249047&r1=249046&r2=249047&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h (original) +++ lldb/trunk/source/Plugins/Language/ObjC/ObjCLanguage.h Thu Oct 1 13:16:18 2015 @@ -146,6 +146,9 @@ public: std::vector<ConstString> GetPossibleFormattersMatches (ValueObject& valobj, lldb::DynamicValueType use_dynamic) override; + std::unique_ptr<TypeScavenger> + GetTypeScavenger () override; + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ Modified: lldb/trunk/source/Target/Language.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Language.cpp?rev=249047&r1=249046&r2=249047&view=diff ============================================================================== --- lldb/trunk/source/Target/Language.cpp (original) +++ lldb/trunk/source/Target/Language.cpp Thu Oct 1 13:16:18 2015 @@ -287,6 +287,34 @@ Language::LanguageIsPascal (LanguageType } } +std::unique_ptr<Language::TypeScavenger> +Language::GetTypeScavenger () +{ + return nullptr; +} + +size_t +Language::TypeScavenger::Find (ExecutionContextScope *exe_scope, + const char *key, + ResultSet &results, + bool append) +{ + if (!exe_scope || !exe_scope->CalculateTarget().get()) + return false; + + if (!key || !key[0]) + return false; + + if (!append) + results.clear(); + + size_t old_size = results.size(); + + if (this->Find_Impl(exe_scope, key, results)) + return results.size() - old_size; + return 0; +} + //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits