<rdar://problem/11870357>

Allow "frame variable" to find ivars without the need for "this->" or "self->".  

llvm-svn: 160211
This commit is contained in:
Greg Clayton 2012-07-14 00:53:55 +00:00
parent c22e8d1192
commit 685c88c5a8
16 changed files with 311 additions and 98 deletions

View File

@ -262,6 +262,22 @@ public:
return m_children.front().get();
}
//------------------------------------------------------------------
/// Get the variable list for this block only.
///
/// @param[in] can_create
/// If \b true, the variables can be parsed if they already
/// haven't been, else the current state of the block will be
/// returned.
///
/// @return
/// A variable list shared pointer that contains all variables
/// for this block.
//------------------------------------------------------------------
lldb::VariableListSP
GetBlockVariableList (bool can_create);
//------------------------------------------------------------------
/// Get the variable list for this block and optionally all child
/// blocks if \a get_child_variables is \b true.
@ -278,7 +294,7 @@ public:
/// point.
///
/// @param[in] add_inline_child_block_variables
/// If this is \b false, no child variables of child blocks
/// If this is \b false, no child variables of child blocks
/// that are inlined functions will be gotten. If \b true then
/// all child variables will be added regardless of whether they
/// come from inlined functions or not.
@ -287,10 +303,6 @@ public:
/// A variable list shared pointer that contains all variables
/// for this block.
//------------------------------------------------------------------
lldb::VariableListSP
GetBlockVariableList (bool can_create);
uint32_t
AppendBlockVariables (bool can_create,
bool get_child_block_variables,
@ -345,7 +357,7 @@ public:
}
clang::DeclContext *
GetClangDeclContextForInlinedFunction();
GetClangDeclContext();
//------------------------------------------------------------------
/// Get the memory cost of this object.

View File

@ -237,6 +237,12 @@ public:
return GetTranslationUnitDecl (getASTContext());
}
static bool
GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx,
lldb::LanguageType &language,
bool &is_instance_method,
ConstString &language_object_name);
static lldb::clang_type_t
CopyType(clang::ASTContext *dest_context,
clang::ASTContext *source_context,

View File

@ -220,6 +220,56 @@ public:
uint32_t
GetResolvedMask () const;
//------------------------------------------------------------------
/// Find a block that defines the function represented by this
/// symbol context.
///
/// If this symbol context points to a block that is an inlined
/// function, or is contained within an inlined function, the block
/// that defines the inlined function is returned.
///
/// If this symbol context has no block in it, or the block is not
/// itself an inlined function block or contained within one, we
/// return the top level function block.
///
/// This is a handy function to call when you want to get the block
/// whose variable list will include the arguments for the function
/// that is represented by this symbol context (whether the function
/// is an inline function or not).
///
/// @return
/// The block object pointer that defines the function that is
/// represented by this symbol context object, NULL otherwise.
//------------------------------------------------------------------
Block *
GetFunctionBlock ();
//------------------------------------------------------------------
/// If this symbol context represents a function that is a method,
/// return true and provide information about the method.
///
/// @param[out] language
/// If \b true is returned, the language for the method.
///
/// @param[out] is_instance_method
/// If \b true is returned, \b true if this is a instance method,
/// \b false if this is a static/class function.
///
/// @param[out] language_object_name
/// If \b true is returned, the name of the artificial variable
/// for the language ("this" for C++, "self" for ObjC).
///
/// @return
/// \b True if this symbol context represents a function that
/// is a method of a class, \b false otherwise.
//------------------------------------------------------------------
bool
GetFunctionMethodInfo (lldb::LanguageType &language,
bool &is_instance_method,
ConstString &language_object_name);
//------------------------------------------------------------------
/// Find a name of the innermost function for the symbol context.
///

View File

@ -50,6 +50,11 @@ public:
lldb::VariableSP
FindVariable (const ConstString& name);
// Find the argument variable that represents the language specific
// object pointer ("this" in C++, or "self" in Objective C).
lldb::VariableSP
FindArtificialObjectVariable (lldb::LanguageType language) const;
uint32_t
FindVariableIndex (const lldb::VariableSP &var_sp);

View File

@ -36,7 +36,8 @@ public:
eExpressionPathOptionCheckPtrVsMember = (1u << 0),
eExpressionPathOptionsNoFragileObjcIvar = (1u << 1),
eExpressionPathOptionsNoSyntheticChildren = (1u << 2),
eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3)
eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3),
eExpressionPathOptionsAllowDirectIVarAccess = (1u << 4)
};
//------------------------------------------------------------------
// Constructors and Destructors

View File

@ -534,7 +534,7 @@ SBFrame::GetValueForVariablePath (const char *var_path, DynamicValueType use_dyn
Error error;
ValueObjectSP value_sp (frame->GetValueForVariableExpressionPath (var_path,
use_dynamic,
StackFrame::eExpressionPathOptionCheckPtrVsMember,
StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
var_sp,
error));
sb_value.SetSP(value_sp);

View File

@ -483,7 +483,8 @@ protected:
else // No regex, either exact variable names or variable expressions.
{
Error error;
uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
lldb::VariableSP var_sp;
valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr,
m_varobj_options.use_dynamic,

View File

@ -1015,7 +1015,8 @@ protected:
// Things have checked out ok...
Error error;
uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
valobj_sp = frame->GetValueForVariableExpressionPath (command.GetArgumentAtIndex(0),
eNoDynamicValues,
expr_path_options,

View File

@ -987,48 +987,6 @@ ScanBracketedRange (const char* var_name_begin,
return true;
}
static ValueObjectSP
ExpandExpressionPath (ValueObject* valobj,
StackFrame* frame,
bool* do_deref_pointer,
const char* var_name_begin,
const char* var_name_final,
Error& error)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
StreamString sstring;
VariableSP var_sp;
if (*do_deref_pointer)
{
if (log)
log->Printf("been told to deref_pointer by caller");
sstring.PutChar('*');
}
else if (valobj->IsDereferenceOfParent() && ClangASTContext::IsPointerType(valobj->GetParent()->GetClangType()) && !valobj->IsArrayItemForPointer())
{
if (log)
log->Printf("decided to deref_pointer myself");
sstring.PutChar('*');
*do_deref_pointer = true;
}
valobj->GetExpressionPath(sstring, true, ValueObject::eGetExpressionPathFormatHonorPointers);
if (log)
log->Printf("expression path to expand in phase 0: %s",sstring.GetData());
sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3);
if (log)
log->Printf("expression path to expand in phase 1: %s",sstring.GetData());
std::string name = std::string(sstring.GetData());
ValueObjectSP target = frame->GetValueForVariableExpressionPath (name.c_str(),
eNoDynamicValues,
0,
var_sp,
error);
return target;
}
static ValueObjectSP
ExpandIndexedExpression (ValueObject* valobj,
uint32_t index,

View File

@ -2443,12 +2443,13 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
if (!sym_ctx.function)
return;
clang::DeclContext *decl_context;
if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo())
decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction();
else
decl_context = sym_ctx.function->GetClangDeclContext();
// Get the block that defines the function
Block *function_block = sym_ctx.GetFunctionBlock();
if (!function_block)
return;
clang::DeclContext *decl_context = function_block->GetClangDeclContext();
if (!decl_context)
return;
@ -2501,12 +2502,13 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
if (!sym_ctx.function)
return;
clang::DeclContext *decl_context;
// Get the block that defines the function
Block *function_block = sym_ctx.GetFunctionBlock();
if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo())
decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction();
else
decl_context = sym_ctx.function->GetClangDeclContext();
if (!function_block)
return;
clang::DeclContext *decl_context = function_block->GetClangDeclContext();
if (!decl_context)
return;

View File

@ -115,13 +115,14 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
if (!sym_ctx.function)
return;
clang::DeclContext *decl_context;
// Find the block that defines the function represented by "sym_ctx"
Block *function_block = sym_ctx.GetFunctionBlock();
if (sym_ctx.block && sym_ctx.block->GetInlinedFunctionInfo())
decl_context = sym_ctx.block->GetClangDeclContextForInlinedFunction();
else
decl_context = sym_ctx.function->GetClangDeclContext();
if (!function_block)
return;
clang::DeclContext *decl_context = function_block->GetClangDeclContext();
if (!decl_context)
return;
@ -131,24 +132,22 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
{
if (m_enforce_valid_object)
{
VariableList *vars = frame->GetVariableList(false);
lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
const char *thisErrorString = "Stopped in a C++ method, but 'this' isn't available; pretending we are in a generic context";
if (!vars)
if (!variable_list_sp)
{
err.SetErrorToGenericError();
err.SetErrorString(thisErrorString);
return;
}
lldb::VariableSP this_var = vars->FindVariable(ConstString("this"));
lldb::VariableSP this_var_sp (variable_list_sp->FindVariable(ConstString("this")));
if (!this_var ||
!this_var->IsInScope(frame) ||
!this_var->LocationIsValidForFrame (frame))
if (!this_var_sp ||
!this_var_sp->IsInScope(frame) ||
!this_var_sp->LocationIsValidForFrame (frame))
{
err.SetErrorToGenericError();
err.SetErrorString(thisErrorString);
return;
}
@ -164,24 +163,22 @@ ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
{
if (m_enforce_valid_object)
{
VariableList *vars = frame->GetVariableList(false);
lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
const char *selfErrorString = "Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context";
if (!vars)
if (!variable_list_sp)
{
err.SetErrorToGenericError();
err.SetErrorString(selfErrorString);
return;
}
lldb::VariableSP self_var = vars->FindVariable(ConstString("self"));
lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self"));
if (!self_var ||
!self_var->IsInScope(frame) ||
!self_var->LocationIsValidForFrame (frame))
if (!self_variable_sp ||
!self_variable_sp->IsInScope(frame) ||
!self_variable_sp->LocationIsValidForFrame (frame))
{
err.SetErrorToGenericError();
err.SetErrorString(selfErrorString);
return;
}

View File

@ -542,7 +542,7 @@ Block::AppendVariables
}
clang::DeclContext *
Block::GetClangDeclContextForInlinedFunction()
Block::GetClangDeclContext()
{
SymbolContext sc;

View File

@ -6330,3 +6330,49 @@ ClangASTContext::GetAsDeclContext (clang::ObjCMethodDecl *objc_method_decl)
return llvm::dyn_cast<clang::DeclContext>(objc_method_decl);
}
bool
ClangASTContext::GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx,
lldb::LanguageType &language,
bool &is_instance_method,
ConstString &language_object_name)
{
language_object_name.Clear();
language = eLanguageTypeUnknown;
is_instance_method = false;
if (decl_ctx)
{
if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx))
{
if (method_decl->isStatic())
{
is_instance_method = false;
}
else
{
language_object_name.SetCString("this");
is_instance_method = true;
}
language = eLanguageTypeC_plus_plus;
return true;
}
else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx))
{
// Both static and instance methods have a "self" object in objective C
language_object_name.SetCString("self");
if (method_decl->isInstanceMethod())
{
is_instance_method = true;
}
else
{
is_instance_method = false;
}
language = eLanguageTypeObjC;
return true;
}
}
return false;
}

View File

@ -13,6 +13,8 @@
#include "lldb/Core/Module.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Symbol.h"
@ -535,7 +537,61 @@ SymbolContext::GetParentOfInlinedScope (const Address &curr_frame_pc,
return false;
}
ConstString
Block *
SymbolContext::GetFunctionBlock ()
{
if (function)
{
if (block)
{
// If this symbol context has a block, check to see if this block
// is itself, or is contained within a block with inlined function
// information. If so, then the inlined block is the block that
// defines the function.
Block *inlined_block = block->GetContainingInlinedBlock();
if (inlined_block)
return inlined_block;
// The block in this symbol context is not inside an inlined
// block, so the block that defines the function is the function's
// top level block, which is returned below.
}
// There is no block information in this symbol context, so we must
// assume that the block that is desired is the top level block of
// the function itself.
return &function->GetBlock(true);
}
return NULL;
}
bool
SymbolContext::GetFunctionMethodInfo (lldb::LanguageType &language,
bool &is_instance_method,
ConstString &language_object_name)
{
Block *function_block = GetFunctionBlock ();
if (function_block)
{
clang::DeclContext *decl_context = function_block->GetClangDeclContext();
if (decl_context)
{
return ClangASTContext::GetClassMethodInfoForDeclContext (decl_context,
language,
is_instance_method,
language_object_name);
}
}
language = eLanguageTypeUnknown;
is_instance_method = false;
language_object_name.Clear();
return false;
}
ConstString
SymbolContext::GetFunctionName (Mangled::NamePreference preference)
{
if (function)

View File

@ -176,3 +176,40 @@ VariableList::Dump(Stream *s, bool show_context) const
}
}
lldb::VariableSP
VariableList::FindArtificialObjectVariable (lldb::LanguageType language) const
{
lldb::VariableSP object_variable_sp;
ConstString object_variable_name;
switch (language)
{
case eLanguageTypeC_plus_plus:
object_variable_name.SetCString("this");
break;
case eLanguageTypeObjC:
case eLanguageTypeObjC_plus_plus:
object_variable_name.SetCString("self");
break;
default:
break;
}
if (object_variable_name)
{
const_iterator pos, end = m_variables.end();
for (pos = m_variables.begin(); pos != end; ++pos)
{
Variable *variable = pos->get();
if (variable->IsArtificial() &&
variable->GetScope() == eValueTypeVariableArgument &&
variable->GetName() == object_variable_name)
{
object_variable_sp = *pos;
break;
}
}
}
return object_variable_sp;
}

View File

@ -513,7 +513,7 @@ StackFrame::GetInScopeVariableList (bool get_file_globals)
ValueObjectSP
StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
DynamicValueType use_dynamic,
uint32_t options,
VariableSP &var_sp,
@ -562,13 +562,42 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx);
var_sp = variable_list->FindVariable(name_const_string);
bool synthetically_added_instance_object = false;
if (var_sp)
{
var_path.erase (0, name_const_string.GetLength ());
}
else if (options & eExpressionPathOptionsAllowDirectIVarAccess)
{
// Check for direct ivars access which helps us with implicit
// access to ivars with the "this->" or "self->"
GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock);
lldb::LanguageType method_language = eLanguageTypeUnknown;
bool is_instance_method = false;
ConstString method_object_name;
if (m_sc.GetFunctionMethodInfo (method_language, is_instance_method, method_object_name))
{
if (is_instance_method && method_object_name)
{
var_sp = variable_list->FindVariable(method_object_name);
if (var_sp)
{
separator_idx = 0;
var_path.insert(0, "->");
synthetically_added_instance_object = true;
}
}
}
}
if (var_sp)
{
valobj_sp = GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (!valobj_sp)
return valobj_sp;
var_path.erase (0, name_const_string.GetLength ());
// We are dumping at least one child
while (separator_idx != std::string::npos)
{
@ -651,23 +680,35 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
if (no_synth_child || !child_valobj_sp)
{
// No child member with name "child_name"
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
if (child_name)
if (synthetically_added_instance_object)
{
error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"",
child_name.GetCString(),
valobj_sp->GetTypeName().AsCString("<invalid type>"),
var_expr_path_strm.GetString().c_str());
// We added a "this->" or "self->" to the beginning of the expression
// and this is the first pointer ivar access, so just return the normal
// error
error.SetErrorStringWithFormat("no variable or instance variable named '%s' found in this frame",
name_const_string.GetCString());
}
else
{
error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"",
var_expr_path_strm.GetString().c_str(),
var_expr_cstr);
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
if (child_name)
{
error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"",
child_name.GetCString(),
valobj_sp->GetTypeName().AsCString("<invalid type>"),
var_expr_path_strm.GetString().c_str());
}
else
{
error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"",
var_expr_path_strm.GetString().c_str(),
var_expr_cstr);
}
}
return ValueObjectSP();
}
}
synthetically_added_instance_object = false;
// Remove the child name from the path
var_path.erase(0, child_name.GetLength());
if (use_dynamic != eNoDynamicValues)