1254721Semaste//===-- Variable.cpp --------------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/Symbol/Variable.h"
11254721Semaste
12254721Semaste#include "lldb/Core/Module.h"
13254721Semaste#include "lldb/Core/Stream.h"
14254721Semaste#include "lldb/Core/RegularExpression.h"
15254721Semaste#include "lldb/Core/ValueObject.h"
16254721Semaste#include "lldb/Core/ValueObjectVariable.h"
17254721Semaste#include "lldb/Symbol/Block.h"
18254721Semaste#include "lldb/Symbol/Function.h"
19254721Semaste#include "lldb/Symbol/SymbolContext.h"
20254721Semaste#include "lldb/Symbol/Type.h"
21254721Semaste#include "lldb/Symbol/VariableList.h"
22254721Semaste#include "lldb/Target/ABI.h"
23254721Semaste#include "lldb/Target/Process.h"
24254721Semaste#include "lldb/Target/RegisterContext.h"
25254721Semaste#include "lldb/Target/StackFrame.h"
26254721Semaste#include "lldb/Target/Thread.h"
27254721Semaste#include "lldb/Target/Target.h"
28254721Semaste
29254721Semasteusing namespace lldb;
30254721Semasteusing namespace lldb_private;
31254721Semaste
32254721Semaste//----------------------------------------------------------------------
33254721Semaste// Variable constructor
34254721Semaste//----------------------------------------------------------------------
35254721SemasteVariable::Variable
36254721Semaste(
37254721Semaste    lldb::user_id_t uid,
38254721Semaste    const char *name,
39254721Semaste    const char *mangled,   // The mangled variable name for variables in namespaces
40254721Semaste    const lldb::SymbolFileTypeSP &symfile_type_sp,
41254721Semaste    ValueType scope,
42254721Semaste    SymbolContextScope *context,
43254721Semaste    Declaration* decl_ptr,
44254721Semaste    const DWARFExpression& location,
45254721Semaste    bool external,
46254721Semaste    bool artificial
47254721Semaste) :
48254721Semaste    UserID(uid),
49254721Semaste    m_name(name),
50254721Semaste    m_mangled (ConstString(mangled), true),
51254721Semaste    m_symfile_type_sp(symfile_type_sp),
52254721Semaste    m_scope(scope),
53254721Semaste    m_owner_scope(context),
54254721Semaste    m_declaration(decl_ptr),
55254721Semaste    m_location(location),
56254721Semaste    m_external(external),
57254721Semaste    m_artificial(artificial)
58254721Semaste{
59254721Semaste}
60254721Semaste
61254721Semaste//----------------------------------------------------------------------
62254721Semaste// Destructor
63254721Semaste//----------------------------------------------------------------------
64254721SemasteVariable::~Variable()
65254721Semaste{
66254721Semaste}
67254721Semaste
68254721Semaste
69254721Semasteconst ConstString&
70254721SemasteVariable::GetName() const
71254721Semaste{
72254721Semaste    if (m_mangled)
73254721Semaste        return m_mangled.GetName();
74254721Semaste    return m_name;
75254721Semaste}
76254721Semaste
77254721Semastebool
78254721SemasteVariable::NameMatches (const RegularExpression& regex) const
79254721Semaste{
80254721Semaste    if (regex.Execute (m_name.AsCString()))
81254721Semaste        return true;
82254721Semaste    return m_mangled.NameMatches (regex);
83254721Semaste}
84254721Semaste
85254721SemasteType *
86254721SemasteVariable::GetType()
87254721Semaste{
88254721Semaste    if (m_symfile_type_sp)
89254721Semaste        return m_symfile_type_sp->GetType();
90254721Semaste    return NULL;
91254721Semaste}
92254721Semaste
93254721Semastevoid
94254721SemasteVariable::Dump(Stream *s, bool show_context) const
95254721Semaste{
96254721Semaste    s->Printf("%p: ", this);
97254721Semaste    s->Indent();
98254721Semaste    *s << "Variable" << (const UserID&)*this;
99254721Semaste
100254721Semaste    if (m_name)
101254721Semaste        *s << ", name = \"" << m_name << "\"";
102254721Semaste
103254721Semaste    if (m_symfile_type_sp)
104254721Semaste    {
105254721Semaste        Type *type = m_symfile_type_sp->GetType();
106254721Semaste        if (type)
107254721Semaste        {
108254721Semaste            *s << ", type = {" << type->GetID() << "} " << (void*)type << " (";
109254721Semaste            type->DumpTypeName(s);
110254721Semaste            s->PutChar(')');
111254721Semaste        }
112254721Semaste    }
113254721Semaste
114254721Semaste    if (m_scope != eValueTypeInvalid)
115254721Semaste    {
116254721Semaste        s->PutCString(", scope = ");
117254721Semaste        switch (m_scope)
118254721Semaste        {
119254721Semaste        case eValueTypeVariableGlobal:       s->PutCString(m_external ? "global" : "static"); break;
120254721Semaste        case eValueTypeVariableArgument:    s->PutCString("parameter"); break;
121254721Semaste        case eValueTypeVariableLocal:        s->PutCString("local"); break;
122254721Semaste        default:            *s << "??? (" << m_scope << ')';
123254721Semaste        }
124254721Semaste    }
125254721Semaste
126254721Semaste    if (show_context && m_owner_scope != NULL)
127254721Semaste    {
128254721Semaste        s->PutCString(", context = ( ");
129254721Semaste        m_owner_scope->DumpSymbolContext(s);
130254721Semaste        s->PutCString(" )");
131254721Semaste    }
132254721Semaste
133254721Semaste    bool show_fullpaths = false;
134254721Semaste    m_declaration.Dump(s, show_fullpaths);
135254721Semaste
136254721Semaste    if (m_location.IsValid())
137254721Semaste    {
138254721Semaste        s->PutCString(", location = ");
139254721Semaste        lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
140254721Semaste        if (m_location.IsLocationList())
141254721Semaste        {
142254721Semaste            SymbolContext variable_sc;
143254721Semaste            m_owner_scope->CalculateSymbolContext(&variable_sc);
144254721Semaste            if (variable_sc.function)
145254721Semaste                loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
146254721Semaste        }
147254721Semaste        ABI *abi = NULL;
148254721Semaste        if (m_owner_scope)
149254721Semaste        {
150254721Semaste            ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
151254721Semaste            if (module_sp)
152254721Semaste                abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
153254721Semaste        }
154254721Semaste        m_location.GetDescription(s, lldb::eDescriptionLevelBrief, loclist_base_addr, abi);
155254721Semaste    }
156254721Semaste
157254721Semaste    if (m_external)
158254721Semaste        s->PutCString(", external");
159254721Semaste
160254721Semaste    if (m_artificial)
161254721Semaste        s->PutCString(", artificial");
162254721Semaste
163254721Semaste    s->EOL();
164254721Semaste}
165254721Semaste
166254721Semastebool
167254721SemasteVariable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
168254721Semaste{
169254721Semaste    bool dumped_declaration_info = false;
170254721Semaste    if (m_owner_scope)
171254721Semaste    {
172254721Semaste        SymbolContext sc;
173254721Semaste        m_owner_scope->CalculateSymbolContext(&sc);
174254721Semaste        sc.block = NULL;
175254721Semaste        sc.line_entry.Clear();
176254721Semaste        bool show_inlined_frames = false;
177254721Semaste
178254721Semaste        dumped_declaration_info = sc.DumpStopContext (s,
179254721Semaste                                                      NULL,
180254721Semaste                                                      Address(),
181254721Semaste                                                      show_fullpaths,
182254721Semaste                                                      show_module,
183254721Semaste                                                      show_inlined_frames);
184254721Semaste
185254721Semaste        if (sc.function)
186254721Semaste            s->PutChar(':');
187254721Semaste    }
188254721Semaste    if (m_declaration.DumpStopContext (s, false))
189254721Semaste        dumped_declaration_info = true;
190254721Semaste    return dumped_declaration_info;
191254721Semaste}
192254721Semaste
193254721Semastesize_t
194254721SemasteVariable::MemorySize() const
195254721Semaste{
196254721Semaste    return sizeof(Variable);
197254721Semaste}
198254721Semaste
199254721Semaste
200254721Semastevoid
201254721SemasteVariable::CalculateSymbolContext (SymbolContext *sc)
202254721Semaste{
203254721Semaste    if (m_owner_scope)
204254721Semaste        m_owner_scope->CalculateSymbolContext(sc);
205254721Semaste    else
206254721Semaste        sc->Clear(false);
207254721Semaste}
208254721Semaste
209254721Semastebool
210254721SemasteVariable::LocationIsValidForFrame (StackFrame *frame)
211254721Semaste{
212254721Semaste    // Is the variable is described by a single location?
213254721Semaste    if (!m_location.IsLocationList())
214254721Semaste    {
215254721Semaste        // Yes it is, the location is valid.
216254721Semaste        return true;
217254721Semaste    }
218254721Semaste
219254721Semaste    if (frame)
220254721Semaste    {
221254721Semaste        Function *function = frame->GetSymbolContext(eSymbolContextFunction).function;
222254721Semaste        if (function)
223254721Semaste        {
224254721Semaste            TargetSP target_sp (frame->CalculateTarget());
225254721Semaste
226254721Semaste            addr_t loclist_base_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress (target_sp.get());
227254721Semaste            if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
228254721Semaste                return false;
229254721Semaste            // It is a location list. We just need to tell if the location
230254721Semaste            // list contains the current address when converted to a load
231254721Semaste            // address
232254721Semaste            return m_location.LocationListContainsAddress (loclist_base_load_addr,
233254721Semaste                                                           frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get()));
234254721Semaste        }
235254721Semaste    }
236254721Semaste    return false;
237254721Semaste}
238254721Semaste
239254721Semastebool
240254721SemasteVariable::LocationIsValidForAddress (const Address &address)
241254721Semaste{
242254721Semaste    // Be sure to resolve the address to section offset prior to
243254721Semaste    // calling this function.
244254721Semaste    if (address.IsSectionOffset())
245254721Semaste    {
246254721Semaste        SymbolContext sc;
247254721Semaste        CalculateSymbolContext(&sc);
248254721Semaste        if (sc.module_sp == address.GetModule())
249254721Semaste        {
250254721Semaste            // Is the variable is described by a single location?
251254721Semaste            if (!m_location.IsLocationList())
252254721Semaste            {
253254721Semaste                // Yes it is, the location is valid.
254254721Semaste                return true;
255254721Semaste            }
256254721Semaste
257254721Semaste            if (sc.function)
258254721Semaste            {
259254721Semaste                addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
260254721Semaste                if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
261254721Semaste                    return false;
262254721Semaste                // It is a location list. We just need to tell if the location
263254721Semaste                // list contains the current address when converted to a load
264254721Semaste                // address
265254721Semaste                return m_location.LocationListContainsAddress (loclist_base_file_addr,
266254721Semaste                                                               address.GetFileAddress());
267254721Semaste            }
268254721Semaste        }
269254721Semaste    }
270254721Semaste    return false;
271254721Semaste}
272254721Semaste
273254721Semastebool
274254721SemasteVariable::IsInScope (StackFrame *frame)
275254721Semaste{
276254721Semaste    switch (m_scope)
277254721Semaste    {
278254721Semaste    case eValueTypeRegister:
279254721Semaste    case eValueTypeRegisterSet:
280254721Semaste        return frame != NULL;
281254721Semaste
282254721Semaste    case eValueTypeConstResult:
283254721Semaste    case eValueTypeVariableGlobal:
284254721Semaste    case eValueTypeVariableStatic:
285254721Semaste        return true;
286254721Semaste
287254721Semaste    case eValueTypeVariableArgument:
288254721Semaste    case eValueTypeVariableLocal:
289254721Semaste        if (frame)
290254721Semaste        {
291254721Semaste            // We don't have a location list, we just need to see if the block
292254721Semaste            // that this variable was defined in is currently
293254721Semaste            Block *deepest_frame_block = frame->GetSymbolContext(eSymbolContextBlock).block;
294254721Semaste            if (deepest_frame_block)
295254721Semaste            {
296254721Semaste                SymbolContext variable_sc;
297254721Semaste                CalculateSymbolContext (&variable_sc);
298254721Semaste                // Check for static or global variable defined at the compile unit
299254721Semaste                // level that wasn't defined in a block
300254721Semaste                if (variable_sc.block == NULL)
301254721Semaste                    return true;
302254721Semaste
303254721Semaste                if (variable_sc.block == deepest_frame_block)
304254721Semaste                    return true;
305254721Semaste                return variable_sc.block->Contains (deepest_frame_block);
306254721Semaste            }
307254721Semaste        }
308254721Semaste        break;
309254721Semaste
310254721Semaste    default:
311254721Semaste        break;
312254721Semaste    }
313254721Semaste    return false;
314254721Semaste}
315254721Semaste
316254721SemasteError
317254721SemasteVariable::GetValuesForVariableExpressionPath (const char *variable_expr_path,
318254721Semaste                                              ExecutionContextScope *scope,
319254721Semaste                                              GetVariableCallback callback,
320254721Semaste                                              void *baton,
321254721Semaste                                              VariableList &variable_list,
322254721Semaste                                              ValueObjectList &valobj_list)
323254721Semaste{
324254721Semaste    Error error;
325254721Semaste    if (variable_expr_path && callback)
326254721Semaste    {
327254721Semaste        switch (variable_expr_path[0])
328254721Semaste        {
329254721Semaste        case '*':
330254721Semaste            {
331254721Semaste                error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
332254721Semaste                                                                      scope,
333254721Semaste                                                                      callback,
334254721Semaste                                                                      baton,
335254721Semaste                                                                      variable_list,
336254721Semaste                                                                      valobj_list);
337254721Semaste                if (error.Success())
338254721Semaste                {
339254721Semaste                    for (uint32_t i=0; i<valobj_list.GetSize(); )
340254721Semaste                    {
341254721Semaste                        Error tmp_error;
342254721Semaste                        ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
343254721Semaste                        if (tmp_error.Fail())
344254721Semaste                        {
345254721Semaste                            variable_list.RemoveVariableAtIndex (i);
346254721Semaste                            valobj_list.RemoveValueObjectAtIndex (i);
347254721Semaste                        }
348254721Semaste                        else
349254721Semaste                        {
350254721Semaste                            valobj_list.SetValueObjectAtIndex (i, valobj_sp);
351254721Semaste                            ++i;
352254721Semaste                        }
353254721Semaste                    }
354254721Semaste                }
355254721Semaste                else
356254721Semaste                {
357254721Semaste                    error.SetErrorString ("unknown error");
358254721Semaste                }
359254721Semaste                return error;
360254721Semaste            }
361254721Semaste            break;
362254721Semaste
363254721Semaste        case '&':
364254721Semaste            {
365254721Semaste                error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
366254721Semaste                                                                      scope,
367254721Semaste                                                                      callback,
368254721Semaste                                                                      baton,
369254721Semaste                                                                      variable_list,
370254721Semaste                                                                      valobj_list);
371254721Semaste                if (error.Success())
372254721Semaste                {
373254721Semaste                    for (uint32_t i=0; i<valobj_list.GetSize(); )
374254721Semaste                    {
375254721Semaste                        Error tmp_error;
376254721Semaste                        ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
377254721Semaste                        if (tmp_error.Fail())
378254721Semaste                        {
379254721Semaste                            variable_list.RemoveVariableAtIndex (i);
380254721Semaste                            valobj_list.RemoveValueObjectAtIndex (i);
381254721Semaste                        }
382254721Semaste                        else
383254721Semaste                        {
384254721Semaste                            valobj_list.SetValueObjectAtIndex (i, valobj_sp);
385254721Semaste                            ++i;
386254721Semaste                        }
387254721Semaste                    }
388254721Semaste                }
389254721Semaste                else
390254721Semaste                {
391254721Semaste                    error.SetErrorString ("unknown error");
392254721Semaste                }
393254721Semaste                return error;
394254721Semaste            }
395254721Semaste            break;
396254721Semaste
397254721Semaste        default:
398254721Semaste            {
399254721Semaste                static RegularExpression g_regex ("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)");
400254721Semaste                RegularExpression::Match regex_match(1);
401254721Semaste                if (g_regex.Execute(variable_expr_path, &regex_match))
402254721Semaste                {
403254721Semaste                    std::string variable_name;
404254721Semaste                    if (regex_match.GetMatchAtIndex(variable_expr_path, 1, variable_name))
405254721Semaste                    {
406254721Semaste                        variable_list.Clear();
407254721Semaste                        if (callback (baton, variable_name.c_str(), variable_list))
408254721Semaste                        {
409254721Semaste                            uint32_t i=0;
410254721Semaste                            while (i < variable_list.GetSize())
411254721Semaste                            {
412254721Semaste                                VariableSP var_sp (variable_list.GetVariableAtIndex (i));
413254721Semaste                                ValueObjectSP valobj_sp;
414254721Semaste                                if (var_sp)
415254721Semaste                                {
416254721Semaste                                    ValueObjectSP variable_valobj_sp(ValueObjectVariable::Create (scope, var_sp));
417254721Semaste                                    if (variable_valobj_sp)
418254721Semaste                                    {
419254721Semaste                                        const char *variable_sub_expr_path = variable_expr_path + variable_name.size();
420254721Semaste                                        if (*variable_sub_expr_path)
421254721Semaste                                        {
422254721Semaste                                            const char* first_unparsed = NULL;
423254721Semaste                                            ValueObject::ExpressionPathScanEndReason reason_to_stop;
424254721Semaste                                            ValueObject::ExpressionPathEndResultType final_value_type;
425254721Semaste                                            ValueObject::GetValueForExpressionPathOptions options;
426254721Semaste                                            ValueObject::ExpressionPathAftermath final_task_on_target;
427254721Semaste
428254721Semaste                                            valobj_sp = variable_valobj_sp->GetValueForExpressionPath (variable_sub_expr_path,
429254721Semaste                                                                                                       &first_unparsed,
430254721Semaste                                                                                                       &reason_to_stop,
431254721Semaste                                                                                                       &final_value_type,
432254721Semaste                                                                                                       options,
433254721Semaste                                                                                                       &final_task_on_target);
434254721Semaste                                            if (!valobj_sp)
435254721Semaste                                            {
436254721Semaste                                                error.SetErrorStringWithFormat ("invalid expression path '%s' for variable '%s'",
437254721Semaste                                                                                variable_sub_expr_path,
438254721Semaste                                                                                var_sp->GetName().GetCString());
439254721Semaste                                            }
440254721Semaste                                        }
441254721Semaste                                        else
442254721Semaste                                        {
443254721Semaste                                            // Just the name of a variable with no extras
444254721Semaste                                            valobj_sp = variable_valobj_sp;
445254721Semaste                                        }
446254721Semaste                                    }
447254721Semaste                                }
448254721Semaste
449254721Semaste                                if (!var_sp || !valobj_sp)
450254721Semaste                                {
451254721Semaste                                    variable_list.RemoveVariableAtIndex (i);
452254721Semaste                                }
453254721Semaste                                else
454254721Semaste                                {
455254721Semaste                                    valobj_list.Append(valobj_sp);
456254721Semaste                                    ++i;
457254721Semaste                                }
458254721Semaste                            }
459254721Semaste
460254721Semaste                            if (variable_list.GetSize() > 0)
461254721Semaste                            {
462254721Semaste                                error.Clear();
463254721Semaste                                return error;
464254721Semaste                            }
465254721Semaste                        }
466254721Semaste                    }
467254721Semaste                }
468254721Semaste                error.SetErrorStringWithFormat ("unable to extract a variable name from '%s'", variable_expr_path);
469254721Semaste            }
470254721Semaste            break;
471254721Semaste        }
472254721Semaste    }
473254721Semaste    error.SetErrorString ("unknown error");
474254721Semaste    return error;
475254721Semaste}
476254721Semaste
477254721Semastebool
478254721SemasteVariable::DumpLocationForAddress (Stream *s, const Address &address)
479254721Semaste{
480254721Semaste    // Be sure to resolve the address to section offset prior to
481254721Semaste    // calling this function.
482254721Semaste    if (address.IsSectionOffset())
483254721Semaste    {
484254721Semaste        SymbolContext sc;
485254721Semaste        CalculateSymbolContext(&sc);
486254721Semaste        if (sc.module_sp == address.GetModule())
487254721Semaste        {
488254721Semaste            ABI *abi = NULL;
489254721Semaste            if (m_owner_scope)
490254721Semaste            {
491254721Semaste                ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
492254721Semaste                if (module_sp)
493254721Semaste                    abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
494254721Semaste            }
495254721Semaste
496254721Semaste            const addr_t file_addr = address.GetFileAddress();
497254721Semaste            if (sc.function)
498254721Semaste            {
499254721Semaste                if (sc.function->GetAddressRange().ContainsFileAddress(address))
500254721Semaste                {
501254721Semaste                    addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
502254721Semaste                    if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
503254721Semaste                        return false;
504254721Semaste                    return m_location.DumpLocationForAddress (s,
505254721Semaste                                                              eDescriptionLevelBrief,
506254721Semaste                                                              loclist_base_file_addr,
507254721Semaste                                                              file_addr,
508254721Semaste                                                              abi);
509254721Semaste                }
510254721Semaste            }
511254721Semaste            return m_location.DumpLocationForAddress (s,
512254721Semaste                                                      eDescriptionLevelBrief,
513254721Semaste                                                      LLDB_INVALID_ADDRESS,
514254721Semaste                                                      file_addr,
515254721Semaste                                                      abi);
516254721Semaste        }
517254721Semaste    }
518254721Semaste    return false;
519254721Semaste}
520254721Semaste
521254721Semaste
522254721Semastestatic void
523254721SemastePrivateAutoComplete (StackFrame *frame,
524254721Semaste                     const std::string &partial_path,
525254721Semaste                     const std::string &prefix_path, // Anything that has been resolved already will be in here
526254721Semaste                     const ClangASTType& clang_type,
527254721Semaste                     StringList &matches,
528254721Semaste                     bool &word_complete);
529254721Semaste
530254721Semastestatic void
531254721SemastePrivateAutoCompleteMembers (StackFrame *frame,
532254721Semaste                            const std::string &partial_member_name,
533254721Semaste                            const std::string &partial_path,
534254721Semaste                            const std::string &prefix_path, // Anything that has been resolved already will be in here
535254721Semaste                            const ClangASTType& clang_type,
536254721Semaste                            StringList &matches,
537254721Semaste                            bool &word_complete);
538254721Semaste
539254721Semastestatic void
540254721SemastePrivateAutoCompleteMembers (StackFrame *frame,
541254721Semaste                            const std::string &partial_member_name,
542254721Semaste                            const std::string &partial_path,
543254721Semaste                            const std::string &prefix_path, // Anything that has been resolved already will be in here
544254721Semaste                            const ClangASTType& clang_type,
545254721Semaste                            StringList &matches,
546254721Semaste                            bool &word_complete)
547254721Semaste{
548254721Semaste
549254721Semaste    // We are in a type parsing child members
550254721Semaste    const uint32_t num_bases = clang_type.GetNumDirectBaseClasses();
551254721Semaste
552254721Semaste    if (num_bases > 0)
553254721Semaste    {
554254721Semaste        for (uint32_t i = 0; i < num_bases; ++i)
555254721Semaste        {
556254721Semaste            ClangASTType base_class_type (clang_type.GetDirectBaseClassAtIndex (i, NULL));
557254721Semaste
558254721Semaste            PrivateAutoCompleteMembers (frame,
559254721Semaste                                        partial_member_name,
560254721Semaste                                        partial_path,
561254721Semaste                                        prefix_path,
562254721Semaste                                        base_class_type.GetCanonicalType(),
563254721Semaste                                        matches,
564254721Semaste                                        word_complete);
565254721Semaste        }
566254721Semaste    }
567254721Semaste
568254721Semaste    const uint32_t num_vbases = clang_type.GetNumVirtualBaseClasses();
569254721Semaste
570254721Semaste    if (num_vbases > 0)
571254721Semaste    {
572254721Semaste        for (uint32_t i = 0; i < num_vbases; ++i)
573254721Semaste        {
574254721Semaste            ClangASTType vbase_class_type (clang_type.GetVirtualBaseClassAtIndex(i,NULL));
575254721Semaste
576254721Semaste            PrivateAutoCompleteMembers (frame,
577254721Semaste                                        partial_member_name,
578254721Semaste                                        partial_path,
579254721Semaste                                        prefix_path,
580254721Semaste                                        vbase_class_type.GetCanonicalType(),
581254721Semaste                                        matches,
582254721Semaste                                        word_complete);
583254721Semaste        }
584254721Semaste    }
585254721Semaste
586254721Semaste    // We are in a type parsing child members
587254721Semaste    const uint32_t num_fields = clang_type.GetNumFields();
588254721Semaste
589254721Semaste    if (num_fields > 0)
590254721Semaste    {
591254721Semaste        for (uint32_t i = 0; i < num_fields; ++i)
592254721Semaste        {
593254721Semaste            std::string member_name;
594254721Semaste
595254721Semaste            ClangASTType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, NULL, NULL, NULL);
596254721Semaste
597254721Semaste            if (partial_member_name.empty() ||
598254721Semaste                member_name.find(partial_member_name) == 0)
599254721Semaste            {
600254721Semaste                if (member_name == partial_member_name)
601254721Semaste                {
602254721Semaste                    PrivateAutoComplete (frame,
603254721Semaste                                         partial_path,
604254721Semaste                                         prefix_path + member_name, // Anything that has been resolved already will be in here
605254721Semaste                                         member_clang_type.GetCanonicalType(),
606254721Semaste                                         matches,
607254721Semaste                                         word_complete);
608254721Semaste                }
609254721Semaste                else
610254721Semaste                {
611254721Semaste                    matches.AppendString (prefix_path + member_name);
612254721Semaste                }
613254721Semaste            }
614254721Semaste        }
615254721Semaste    }
616254721Semaste}
617254721Semaste
618254721Semastestatic void
619254721SemastePrivateAutoComplete (StackFrame *frame,
620254721Semaste                     const std::string &partial_path,
621254721Semaste                     const std::string &prefix_path, // Anything that has been resolved already will be in here
622254721Semaste                     const ClangASTType& clang_type,
623254721Semaste                     StringList &matches,
624254721Semaste                     bool &word_complete)
625254721Semaste{
626254721Semaste//    printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str());
627254721Semaste    std::string remaining_partial_path;
628254721Semaste
629254721Semaste    const lldb::TypeClass type_class = clang_type.GetTypeClass();
630254721Semaste    if (partial_path.empty())
631254721Semaste    {
632254721Semaste        if (clang_type.IsValid())
633254721Semaste        {
634254721Semaste            switch (type_class)
635254721Semaste            {
636254721Semaste                default:
637254721Semaste                case eTypeClassArray:
638254721Semaste                case eTypeClassBlockPointer:
639254721Semaste                case eTypeClassBuiltin:
640254721Semaste                case eTypeClassComplexFloat:
641254721Semaste                case eTypeClassComplexInteger:
642254721Semaste                case eTypeClassEnumeration:
643254721Semaste                case eTypeClassFunction:
644254721Semaste                case eTypeClassMemberPointer:
645254721Semaste                case eTypeClassReference:
646254721Semaste                case eTypeClassTypedef:
647254721Semaste                case eTypeClassVector:
648254721Semaste                    {
649254721Semaste                        matches.AppendString (prefix_path);
650254721Semaste                        word_complete = matches.GetSize() == 1;
651254721Semaste                    }
652254721Semaste                    break;
653254721Semaste
654254721Semaste                case eTypeClassClass:
655254721Semaste                case eTypeClassStruct:
656254721Semaste                case eTypeClassUnion:
657254721Semaste                    if (prefix_path.back() != '.')
658254721Semaste                        matches.AppendString (prefix_path + '.');
659254721Semaste                    break;
660254721Semaste
661254721Semaste                case eTypeClassObjCObject:
662254721Semaste                case eTypeClassObjCInterface:
663254721Semaste                    break;
664254721Semaste                case eTypeClassObjCObjectPointer:
665254721Semaste                case eTypeClassPointer:
666254721Semaste                    {
667254721Semaste                        bool omit_empty_base_classes = true;
668254721Semaste                        if (clang_type.GetNumChildren (omit_empty_base_classes) > 0)
669254721Semaste                            matches.AppendString (prefix_path + "->");
670254721Semaste                        else
671254721Semaste                        {
672254721Semaste                            matches.AppendString (prefix_path);
673254721Semaste                            word_complete = true;
674254721Semaste                        }
675254721Semaste                    }
676254721Semaste                    break;
677254721Semaste            }
678254721Semaste        }
679254721Semaste        else
680254721Semaste        {
681254721Semaste            if (frame)
682254721Semaste            {
683254721Semaste                const bool get_file_globals = true;
684254721Semaste
685254721Semaste                VariableList *variable_list = frame->GetVariableList(get_file_globals);
686254721Semaste
687263363Semaste                if (variable_list)
688254721Semaste                {
689263363Semaste                    const size_t num_variables = variable_list->GetSize();
690263363Semaste                    for (size_t i=0; i<num_variables; ++i)
691263363Semaste                    {
692263363Semaste                        Variable *variable = variable_list->GetVariableAtIndex(i).get();
693263363Semaste                        matches.AppendString (variable->GetName().AsCString());
694263363Semaste                    }
695254721Semaste                }
696254721Semaste            }
697254721Semaste        }
698254721Semaste    }
699254721Semaste    else
700254721Semaste    {
701254721Semaste        const char ch = partial_path[0];
702254721Semaste        switch (ch)
703254721Semaste        {
704254721Semaste        case '*':
705254721Semaste            if (prefix_path.empty())
706254721Semaste            {
707254721Semaste                PrivateAutoComplete (frame,
708254721Semaste                                     partial_path.substr(1),
709254721Semaste                                     std::string("*"),
710254721Semaste                                     clang_type,
711254721Semaste                                     matches,
712254721Semaste                                     word_complete);
713254721Semaste            }
714254721Semaste            break;
715254721Semaste
716254721Semaste        case '&':
717254721Semaste            if (prefix_path.empty())
718254721Semaste            {
719254721Semaste                PrivateAutoComplete (frame,
720254721Semaste                                     partial_path.substr(1),
721254721Semaste                                     std::string("&"),
722254721Semaste                                     clang_type,
723254721Semaste                                     matches,
724254721Semaste                                     word_complete);
725254721Semaste            }
726254721Semaste            break;
727254721Semaste
728254721Semaste        case '-':
729254721Semaste            if (partial_path[1] == '>' && !prefix_path.empty())
730254721Semaste            {
731254721Semaste                switch (type_class)
732254721Semaste                {
733254721Semaste                    case lldb::eTypeClassPointer:
734254721Semaste                        {
735254721Semaste                            ClangASTType pointee_type(clang_type.GetPointeeType());
736254721Semaste                            if (partial_path[2])
737254721Semaste                            {
738254721Semaste                                // If there is more after the "->", then search deeper
739254721Semaste                                PrivateAutoComplete (frame,
740254721Semaste                                                     partial_path.substr(2),
741254721Semaste                                                     prefix_path + "->",
742254721Semaste                                                     pointee_type.GetCanonicalType(),
743254721Semaste                                                     matches,
744254721Semaste                                                     word_complete);
745254721Semaste                            }
746254721Semaste                            else
747254721Semaste                            {
748254721Semaste                                // Nothing after the "->", so list all members
749254721Semaste                                PrivateAutoCompleteMembers (frame,
750254721Semaste                                                            std::string(),
751254721Semaste                                                            std::string(),
752254721Semaste                                                            prefix_path + "->",
753254721Semaste                                                            pointee_type.GetCanonicalType(),
754254721Semaste                                                            matches,
755254721Semaste                                                            word_complete);
756254721Semaste                            }
757254721Semaste                        }
758254721Semaste                    default:
759254721Semaste                        break;
760254721Semaste                }
761254721Semaste            }
762254721Semaste            break;
763254721Semaste
764254721Semaste        case '.':
765254721Semaste            if (clang_type.IsValid())
766254721Semaste            {
767254721Semaste                switch (type_class)
768254721Semaste                {
769254721Semaste                    case lldb::eTypeClassUnion:
770254721Semaste                    case lldb::eTypeClassStruct:
771254721Semaste                    case lldb::eTypeClassClass:
772254721Semaste                        if (partial_path[1])
773254721Semaste                        {
774254721Semaste                            // If there is more after the ".", then search deeper
775254721Semaste                            PrivateAutoComplete (frame,
776254721Semaste                                                 partial_path.substr(1),
777254721Semaste                                                 prefix_path + ".",
778254721Semaste                                                 clang_type,
779254721Semaste                                                 matches,
780254721Semaste                                                 word_complete);
781254721Semaste
782254721Semaste                        }
783254721Semaste                        else
784254721Semaste                        {
785254721Semaste                            // Nothing after the ".", so list all members
786254721Semaste                            PrivateAutoCompleteMembers (frame,
787254721Semaste                                                        std::string(),
788254721Semaste                                                        partial_path,
789254721Semaste                                                        prefix_path + ".",
790254721Semaste                                                        clang_type,
791254721Semaste                                                        matches,
792254721Semaste                                                        word_complete);
793254721Semaste                        }
794254721Semaste                    default:
795254721Semaste                        break;
796254721Semaste                }
797254721Semaste            }
798254721Semaste            break;
799254721Semaste        default:
800254721Semaste            if (isalpha(ch) || ch == '_' || ch == '$')
801254721Semaste            {
802254721Semaste                const size_t partial_path_len = partial_path.size();
803254721Semaste                size_t pos = 1;
804254721Semaste                while (pos < partial_path_len)
805254721Semaste                {
806254721Semaste                    const char curr_ch = partial_path[pos];
807254721Semaste                    if (isalnum(curr_ch) || curr_ch == '_'  || curr_ch == '$')
808254721Semaste                    {
809254721Semaste                        ++pos;
810254721Semaste                        continue;
811254721Semaste                    }
812254721Semaste                    break;
813254721Semaste                }
814254721Semaste
815254721Semaste                std::string token(partial_path, 0, pos);
816254721Semaste                remaining_partial_path = partial_path.substr(pos);
817254721Semaste
818254721Semaste                if (clang_type.IsValid())
819254721Semaste                {
820254721Semaste                    PrivateAutoCompleteMembers (frame,
821254721Semaste                                                token,
822254721Semaste                                                remaining_partial_path,
823254721Semaste                                                prefix_path,
824254721Semaste                                                clang_type,
825254721Semaste                                                matches,
826254721Semaste                                                word_complete);
827254721Semaste                }
828254721Semaste                else if (frame)
829254721Semaste                {
830254721Semaste                    // We haven't found our variable yet
831254721Semaste                    const bool get_file_globals = true;
832254721Semaste
833254721Semaste                    VariableList *variable_list = frame->GetVariableList(get_file_globals);
834254721Semaste
835269024Semaste                    if (!variable_list)
836269024Semaste                        break;
837269024Semaste
838254721Semaste                    const size_t num_variables = variable_list->GetSize();
839254721Semaste                    for (size_t i=0; i<num_variables; ++i)
840254721Semaste                    {
841254721Semaste                        Variable *variable = variable_list->GetVariableAtIndex(i).get();
842269024Semaste
843269024Semaste                        if (!variable)
844269024Semaste                            continue;
845269024Semaste
846254721Semaste                        const char *variable_name = variable->GetName().AsCString();
847254721Semaste                        if (strstr(variable_name, token.c_str()) == variable_name)
848254721Semaste                        {
849254721Semaste                            if (strcmp (variable_name, token.c_str()) == 0)
850254721Semaste                            {
851254721Semaste                                Type *variable_type = variable->GetType();
852254721Semaste                                if (variable_type)
853254721Semaste                                {
854254721Semaste                                    ClangASTType variable_clang_type (variable_type->GetClangForwardType());
855254721Semaste                                    PrivateAutoComplete (frame,
856254721Semaste                                                         remaining_partial_path,
857254721Semaste                                                         prefix_path + token, // Anything that has been resolved already will be in here
858254721Semaste                                                         variable_clang_type.GetCanonicalType(),
859254721Semaste                                                         matches,
860254721Semaste                                                         word_complete);
861254721Semaste                                }
862254721Semaste                                else
863254721Semaste                                {
864254721Semaste                                    matches.AppendString (prefix_path + variable_name);
865254721Semaste                                }
866254721Semaste                            }
867254721Semaste                            else if (remaining_partial_path.empty())
868254721Semaste                            {
869254721Semaste                                matches.AppendString (prefix_path + variable_name);
870254721Semaste                            }
871254721Semaste                        }
872254721Semaste                    }
873254721Semaste                }
874254721Semaste            }
875254721Semaste            break;
876254721Semaste        }
877254721Semaste    }
878254721Semaste}
879254721Semaste
880254721Semaste
881254721Semaste
882254721Semastesize_t
883254721SemasteVariable::AutoComplete (const ExecutionContext &exe_ctx,
884254721Semaste                        const char *partial_path_cstr,
885254721Semaste                        StringList &matches,
886254721Semaste                        bool &word_complete)
887254721Semaste{
888254721Semaste    word_complete = false;
889254721Semaste    std::string partial_path;
890254721Semaste    std::string prefix_path;
891254721Semaste    ClangASTType clang_type;
892254721Semaste    if (partial_path_cstr && partial_path_cstr[0])
893254721Semaste        partial_path = partial_path_cstr;
894254721Semaste
895254721Semaste    PrivateAutoComplete (exe_ctx.GetFramePtr(),
896254721Semaste                         partial_path,
897254721Semaste                         prefix_path,
898254721Semaste                         clang_type,
899254721Semaste                         matches,
900254721Semaste                         word_complete);
901254721Semaste
902254721Semaste    return matches.GetSize();
903254721Semaste}
904254721Semaste
905