[Lldb-commits] [lldb] r181850 - A first pass at auto completion for variables and their children. This is currently hooked up for "frame variable" only. With a little work we can also enable it for the "expression" command and also for other things.
Greg Clayton
gclayton at apple.com
Tue May 14 16:43:18 PDT 2013
Author: gclayton
Date: Tue May 14 18:43:18 2013
New Revision: 181850
URL: http://llvm.org/viewvc/llvm-project?rev=181850&view=rev
Log:
A first pass at auto completion for variables and their children. This is currently hooked up for "frame variable" only. With a little work we can also enable it for the "expression" command and also for other things.
Modified:
lldb/trunk/include/lldb/Interpreter/CommandCompletions.h
lldb/trunk/include/lldb/Symbol/ClangASTType.h
lldb/trunk/include/lldb/Symbol/Variable.h
lldb/trunk/source/Commands/CommandCompletions.cpp
lldb/trunk/source/Commands/CommandObjectFrame.cpp
lldb/trunk/source/Symbol/ClangASTType.cpp
lldb/trunk/source/Symbol/Variable.cpp
Modified: lldb/trunk/include/lldb/Interpreter/CommandCompletions.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandCompletions.h?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandCompletions.h (original)
+++ lldb/trunk/include/lldb/Interpreter/CommandCompletions.h Tue May 14 18:43:18 2013
@@ -49,10 +49,11 @@ public:
eSettingsNameCompletion = (1u << 5),
ePlatformPluginCompletion = (1u << 6),
eArchitectureCompletion = (1u << 7),
+ eVariablePathCompletion = (1u << 8),
// This item serves two purposes. It is the last element in the enum,
// so you can add custom enums starting from here in your Option class.
// Also if you & in this bit the base code will not process the option.
- eCustomCompletion = (1u << 8)
+ eCustomCompletion = (1u << 9)
} CommonCompletionTypes;
@@ -145,7 +146,16 @@ public:
SearchFilter *searcher,
bool &word_complete,
lldb_private::StringList &matches);
-
+
+ static int
+ VariablePath (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
//----------------------------------------------------------------------
// The Completer class is a convenient base class for building searchers
// that go along with the SearchFilter passed to the standard Completer
Modified: lldb/trunk/include/lldb/Symbol/ClangASTType.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTType.h?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/ClangASTType.h (original)
+++ lldb/trunk/include/lldb/Symbol/ClangASTType.h Tue May 14 18:43:18 2013
@@ -76,6 +76,15 @@ public:
return m_ast;
}
+ static ClangASTType
+ GetCanonicalType (clang::ASTContext *ast, lldb::clang_type_t clang_type);
+
+ ClangASTType
+ GetCanonicalType ()
+ {
+ return GetCanonicalType (GetASTContext(), GetOpaqueQualType());
+ }
+
ConstString
GetConstTypeName ();
@@ -137,6 +146,12 @@ public:
GetTypeClass (clang::ASTContext *ast_context,
lldb::clang_type_t clang_type);
+ lldb::TypeClass
+ GetTypeClass () const
+ {
+ return GetTypeClass (GetASTContext(), GetOpaqueQualType());
+ }
+
void
DumpValue (ExecutionContext *exe_ctx,
Stream *s,
@@ -310,7 +325,7 @@ public:
StreamString &new_value);
lldb::clang_type_t
- GetPointeeType ();
+ GetPointeeType () const;
static lldb::clang_type_t
GetPointeeType (lldb::clang_type_t opaque_clang_qual_type);
Modified: lldb/trunk/include/lldb/Symbol/Variable.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/Variable.h?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/Variable.h (original)
+++ lldb/trunk/include/lldb/Symbol/Variable.h Tue May 14 18:43:18 2013
@@ -157,6 +157,12 @@ public:
VariableList &variable_list,
ValueObjectList &valobj_list);
+ static size_t
+ AutoComplete (const ExecutionContext &exe_ctx,
+ const char *name,
+ StringList &matches,
+ bool &word_complete);
+
protected:
ConstString m_name; // The basename of the variable (no namespaces)
Mangled m_mangled; // The mangled name of the variable
Modified: lldb/trunk/source/Commands/CommandCompletions.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandCompletions.cpp?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandCompletions.cpp (original)
+++ lldb/trunk/source/Commands/CommandCompletions.cpp Tue May 14 18:43:18 2013
@@ -27,6 +27,7 @@
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Variable.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/CleanUp.h"
@@ -44,6 +45,7 @@ CommandCompletions::g_common_completions
{eSettingsNameCompletion, CommandCompletions::SettingsNames},
{ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
{eArchitectureCompletion, CommandCompletions::ArchitectureNames},
+ {eVariablePathCompletion, CommandCompletions::VariablePath},
{eNoCompletion, NULL} // This one has to be last in the list.
};
@@ -459,6 +461,19 @@ CommandCompletions::ArchitectureNames (C
}
+int
+CommandCompletions::VariablePath (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete);
+}
+
+
CommandCompletions::Completer::Completer
(
CommandInterpreter &interpreter,
Modified: lldb/trunk/source/Commands/CommandObjectFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectFrame.cpp?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectFrame.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectFrame.cpp Tue May 14 18:43:18 2013
@@ -345,6 +345,32 @@ public:
{
return &m_option_group;
}
+
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard source file completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eVariablePathCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
protected:
virtual bool
Modified: lldb/trunk/source/Symbol/ClangASTType.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTType.cpp?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/ClangASTType.cpp (original)
+++ lldb/trunk/source/Symbol/ClangASTType.cpp Tue May 14 18:43:18 2013
@@ -79,6 +79,14 @@ ClangASTType::GetTypeNameForOpaqueQualTy
return GetTypeNameForQualType (ast, clang::QualType::getFromOpaquePtr(opaque_qual_type));
}
+ClangASTType
+ClangASTType::GetCanonicalType (clang::ASTContext *ast, lldb::clang_type_t opaque_qual_type)
+{
+ if (ast && opaque_qual_type)
+ return ClangASTType (ast,
+ clang::QualType::getFromOpaquePtr(opaque_qual_type).getCanonicalType().getAsOpaquePtr());
+ return ClangASTType();
+}
ConstString
ClangASTType::GetConstTypeName ()
@@ -124,7 +132,7 @@ ClangASTType::GetConstTypeName (clang::A
}
clang_type_t
-ClangASTType::GetPointeeType ()
+ClangASTType::GetPointeeType () const
{
return GetPointeeType (m_type);
}
Modified: lldb/trunk/source/Symbol/Variable.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/Variable.cpp?rev=181850&r1=181849&r2=181850&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/Variable.cpp (original)
+++ lldb/trunk/source/Symbol/Variable.cpp Tue May 14 18:43:18 2013
@@ -516,6 +516,397 @@ Variable::DumpLocationForAddress (Stream
}
}
return false;
+}
+
+
+static void
+PrivateAutoComplete (StackFrame *frame,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete);
+
+static void
+PrivateAutoCompleteMembers (StackFrame *frame,
+ const std::string &partial_member_name,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete);
+
+static void
+PrivateAutoCompleteMembers (StackFrame *frame,
+ const std::string &partial_member_name,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete)
+{
+
+ // We are in a type parsing child members
+ const uint32_t num_bases = ClangASTContext::GetNumDirectBaseClasses(clang_type.GetASTContext(),
+ clang_type.GetOpaqueQualType());
+
+ if (num_bases > 0)
+ {
+ for (uint32_t i = 0; i < num_bases; ++i)
+ {
+ ClangASTType base_class_type (clang_type.GetASTContext(),
+ ClangASTContext::GetDirectBaseClassAtIndex (clang_type.GetASTContext(),
+ clang_type.GetOpaqueQualType(),
+ i,
+ NULL));
+
+ PrivateAutoCompleteMembers (frame,
+ partial_member_name,
+ partial_path,
+ prefix_path,
+ base_class_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ }
+
+ const uint32_t num_vbases = ClangASTContext::GetNumVirtualBaseClasses(clang_type.GetASTContext(),
+ clang_type.GetOpaqueQualType());
+
+ if (num_vbases > 0)
+ {
+ for (uint32_t i = 0; i < num_vbases; ++i)
+ {
+ ClangASTType vbase_class_type (clang_type.GetASTContext(),
+ ClangASTContext::GetVirtualBaseClassAtIndex(clang_type.GetASTContext(),
+ clang_type.GetOpaqueQualType(),
+ i,
+ NULL));
+
+ PrivateAutoCompleteMembers (frame,
+ partial_member_name,
+ partial_path,
+ prefix_path,
+ vbase_class_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ }
+
+ // We are in a type parsing child members
+ const uint32_t num_fields = ClangASTContext::GetNumFields(clang_type.GetASTContext(),
+ clang_type.GetOpaqueQualType());
+
+ if (num_fields > 0)
+ {
+ for (uint32_t i = 0; i < num_fields; ++i)
+ {
+ std::string member_name;
+
+ lldb::clang_type_t member_type = ClangASTContext::GetFieldAtIndex (clang_type.GetASTContext(),
+ clang_type.GetOpaqueQualType(),
+ i,
+ member_name,
+ NULL,
+ NULL,
+ NULL);
+
+ if (partial_member_name.empty() ||
+ member_name.find(partial_member_name) == 0)
+ {
+ if (member_name == partial_member_name)
+ {
+ ClangASTType member_clang_type (clang_type.GetASTContext(), member_type);
+ PrivateAutoComplete (frame,
+ partial_path,
+ prefix_path + member_name, // Anything that has been resolved already will be in here
+ member_clang_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ else
+ {
+ matches.AppendString (prefix_path + member_name);
+ }
+ }
+ }
+ }
+}
+
+static void
+PrivateAutoComplete (StackFrame *frame,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete)
+{
+// printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str());
+ std::string remaining_partial_path;
+
+ const lldb::TypeClass type_class = clang_type.GetTypeClass();
+ if (partial_path.empty())
+ {
+ if (clang_type.IsValid())
+ {
+ switch (type_class)
+ {
+ default:
+ case eTypeClassArray:
+ case eTypeClassBlockPointer:
+ case eTypeClassBuiltin:
+ case eTypeClassComplexFloat:
+ case eTypeClassComplexInteger:
+ case eTypeClassEnumeration:
+ case eTypeClassFunction:
+ case eTypeClassMemberPointer:
+ case eTypeClassReference:
+ case eTypeClassTypedef:
+ case eTypeClassVector:
+ {
+ matches.AppendString (prefix_path);
+ word_complete = matches.GetSize() == 1;
+ }
+ break;
+
+ case eTypeClassClass:
+ case eTypeClassStruct:
+ case eTypeClassUnion:
+ if (prefix_path.back() != '.')
+ matches.AppendString (prefix_path + '.');
+ break;
+
+ case eTypeClassObjCObject:
+ case eTypeClassObjCInterface:
+ break;
+ case eTypeClassObjCObjectPointer:
+ case eTypeClassPointer:
+ {
+ bool omit_empty_base_classes = true;
+ if (ClangASTContext::GetNumChildren (clang_type.GetASTContext(), clang_type.GetPointeeType(), omit_empty_base_classes) > 0)
+ matches.AppendString (prefix_path + "->");
+ else
+ {
+ matches.AppendString (prefix_path);
+ word_complete = true;
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (frame)
+ {
+ const bool get_file_globals = true;
+
+ VariableList *variable_list = frame->GetVariableList(get_file_globals);
+
+ const size_t num_variables = variable_list->GetSize();
+ for (size_t i=0; i<num_variables; ++i)
+ {
+ Variable *variable = variable_list->GetVariableAtIndex(i).get();
+ matches.AppendString (variable->GetName().AsCString());
+ }
+ }
+ }
+ }
+ else
+ {
+ const char ch = partial_path[0];
+ switch (ch)
+ {
+ case '*':
+ if (prefix_path.empty())
+ {
+ PrivateAutoComplete (frame,
+ partial_path.substr(1),
+ std::string("*"),
+ clang_type,
+ matches,
+ word_complete);
+ }
+ break;
+
+ case '&':
+ if (prefix_path.empty())
+ {
+ PrivateAutoComplete (frame,
+ partial_path.substr(1),
+ std::string("&"),
+ clang_type,
+ matches,
+ word_complete);
+ }
+ break;
+
+ case '-':
+ if (partial_path[1] == '>' && !prefix_path.empty())
+ {
+ switch (type_class)
+ {
+ case lldb::eTypeClassPointer:
+ {
+ ClangASTType pointee_type(clang_type.GetASTContext(), clang_type.GetPointeeType());
+ if (partial_path[2])
+ {
+ // If there is more after the "->", then search deeper
+ PrivateAutoComplete (frame,
+ partial_path.substr(2),
+ prefix_path + "->",
+ pointee_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ else
+ {
+ // Nothing after the "->", so list all members
+ PrivateAutoCompleteMembers (frame,
+ std::string(),
+ std::string(),
+ prefix_path + "->",
+ pointee_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ }
+ default:
+ break;
+ }
+ }
+ break;
+
+ case '.':
+ if (clang_type.IsValid())
+ {
+ switch (type_class)
+ {
+ case lldb::eTypeClassUnion:
+ case lldb::eTypeClassStruct:
+ case lldb::eTypeClassClass:
+ if (partial_path[1])
+ {
+ // If there is more after the ".", then search deeper
+ PrivateAutoComplete (frame,
+ partial_path.substr(1),
+ prefix_path + ".",
+ clang_type,
+ matches,
+ word_complete);
+
+ }
+ else
+ {
+ // Nothing after the ".", so list all members
+ PrivateAutoCompleteMembers (frame,
+ std::string(),
+ partial_path,
+ prefix_path + ".",
+ clang_type,
+ matches,
+ word_complete);
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ if (isalpha(ch) || ch == '_' || ch == '$')
+ {
+ const size_t partial_path_len = partial_path.size();
+ size_t pos = 1;
+ while (pos < partial_path_len)
+ {
+ const char curr_ch = partial_path[pos];
+ if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$')
+ {
+ ++pos;
+ continue;
+ }
+ break;
+ }
+
+ std::string token(partial_path, 0, pos);
+ remaining_partial_path = partial_path.substr(pos);
+
+ if (clang_type.IsValid())
+ {
+ PrivateAutoCompleteMembers (frame,
+ token,
+ remaining_partial_path,
+ prefix_path,
+ clang_type,
+ matches,
+ word_complete);
+ }
+ else if (frame)
+ {
+ // We haven't found our variable yet
+ const bool get_file_globals = true;
+
+ VariableList *variable_list = frame->GetVariableList(get_file_globals);
+
+ const size_t num_variables = variable_list->GetSize();
+ for (size_t i=0; i<num_variables; ++i)
+ {
+ Variable *variable = variable_list->GetVariableAtIndex(i).get();
+ const char *variable_name = variable->GetName().AsCString();
+ if (strstr(variable_name, token.c_str()) == variable_name)
+ {
+ if (strcmp (variable_name, token.c_str()) == 0)
+ {
+ Type *variable_type = variable->GetType();
+ if (variable_type)
+ {
+ ClangASTType variable_clang_type (variable_type->GetClangAST(), variable_type->GetClangForwardType());
+ PrivateAutoComplete (frame,
+ remaining_partial_path,
+ prefix_path + token, // Anything that has been resolved already will be in here
+ variable_clang_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ else
+ {
+ matches.AppendString (prefix_path + variable_name);
+ }
+ }
+ else if (remaining_partial_path.empty())
+ {
+ matches.AppendString (prefix_path + variable_name);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+
+size_t
+Variable::AutoComplete (const ExecutionContext &exe_ctx,
+ const char *partial_path_cstr,
+ StringList &matches,
+ bool &word_complete)
+{
+ word_complete = false;
+ std::string partial_path;
+ std::string prefix_path;
+ ClangASTType clang_type;
+ if (partial_path_cstr && partial_path_cstr[0])
+ partial_path = partial_path_cstr;
+
+ PrivateAutoComplete (exe_ctx.GetFramePtr(),
+ partial_path,
+ prefix_path,
+ clang_type,
+ matches,
+ word_complete);
+ return matches.GetSize();
}
More information about the lldb-commits
mailing list