forked from OSchip/llvm-project
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.
llvm-svn: 181850
This commit is contained in:
parent
c750907218
commit
f21feadcd9
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (CommandInterpreter &interpreter,
|
|||
}
|
||||
|
||||
|
||||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -79,6 +79,14 @@ ClangASTType::GetTypeNameForOpaqueQualType (clang::ASTContext *ast, clang_type_t
|
|||
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::ASTContext *ast, clang_type_t clang_type)
|
|||
}
|
||||
|
||||
clang_type_t
|
||||
ClangASTType::GetPointeeType ()
|
||||
ClangASTType::GetPointeeType () const
|
||||
{
|
||||
return GetPointeeType (m_type);
|
||||
}
|
||||
|
|
|
@ -516,6 +516,397 @@ Variable::DumpLocationForAddress (Stream *s, const Address &address)
|
|||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue