1 //===-- Variable.cpp --------------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Symbol/Variable.h"
11
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Stream.h"
14 #include "lldb/Core/RegularExpression.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Core/ValueObjectVariable.h"
17 #include "lldb/Symbol/Block.h"
18 #include "lldb/Symbol/CompileUnit.h"
19 #include "lldb/Symbol/Function.h"
20 #include "lldb/Symbol/SymbolContext.h"
21 #include "lldb/Symbol/Type.h"
22 #include "lldb/Symbol/VariableList.h"
23 #include "lldb/Target/ABI.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/RegisterContext.h"
26 #include "lldb/Target/StackFrame.h"
27 #include "lldb/Target/Thread.h"
28 #include "lldb/Target/Target.h"
29
30 using namespace lldb;
31 using namespace lldb_private;
32
33 //----------------------------------------------------------------------
34 // Variable constructor
35 //----------------------------------------------------------------------
Variable(lldb::user_id_t uid,const char * name,const char * mangled,const lldb::SymbolFileTypeSP & symfile_type_sp,ValueType scope,SymbolContextScope * context,Declaration * decl_ptr,const DWARFExpression & location,bool external,bool artificial)36 Variable::Variable
37 (
38 lldb::user_id_t uid,
39 const char *name,
40 const char *mangled, // The mangled or fully qualified name of the variable.
41 const lldb::SymbolFileTypeSP &symfile_type_sp,
42 ValueType scope,
43 SymbolContextScope *context,
44 Declaration* decl_ptr,
45 const DWARFExpression& location,
46 bool external,
47 bool artificial
48 ) :
49 UserID(uid),
50 m_name(name),
51 m_mangled (ConstString(mangled)),
52 m_symfile_type_sp(symfile_type_sp),
53 m_scope(scope),
54 m_owner_scope(context),
55 m_declaration(decl_ptr),
56 m_location(location),
57 m_external(external),
58 m_artificial(artificial)
59 {
60 }
61
62 //----------------------------------------------------------------------
63 // Destructor
64 //----------------------------------------------------------------------
~Variable()65 Variable::~Variable()
66 {
67 }
68
69 lldb::LanguageType
GetLanguage() const70 Variable::GetLanguage () const
71 {
72 SymbolContext variable_sc;
73 m_owner_scope->CalculateSymbolContext(&variable_sc);
74 if (variable_sc.comp_unit)
75 return variable_sc.comp_unit->GetLanguage();
76 return lldb::eLanguageTypeUnknown;
77 }
78
79
80
81 ConstString
GetName() const82 Variable::GetName() const
83 {
84 ConstString name = m_mangled.GetName(GetLanguage());
85 if (name)
86 return name;
87 return m_name;
88 }
89
90 bool
NameMatches(const ConstString & name) const91 Variable::NameMatches (const ConstString &name) const
92 {
93 if (m_name == name)
94 return true;
95 SymbolContext variable_sc;
96 m_owner_scope->CalculateSymbolContext(&variable_sc);
97
98 LanguageType language = eLanguageTypeUnknown;
99 if (variable_sc.comp_unit)
100 language = variable_sc.comp_unit->GetLanguage();
101 return m_mangled.NameMatches (name, language);
102 }
103 bool
NameMatches(const RegularExpression & regex) const104 Variable::NameMatches (const RegularExpression& regex) const
105 {
106 if (regex.Execute (m_name.AsCString()))
107 return true;
108 if (m_mangled)
109 return m_mangled.NameMatches (regex, GetLanguage());
110 return false;
111 }
112
113 Type *
GetType()114 Variable::GetType()
115 {
116 if (m_symfile_type_sp)
117 return m_symfile_type_sp->GetType();
118 return nullptr;
119 }
120
121 void
Dump(Stream * s,bool show_context) const122 Variable::Dump(Stream *s, bool show_context) const
123 {
124 s->Printf("%p: ", static_cast<const void*>(this));
125 s->Indent();
126 *s << "Variable" << (const UserID&)*this;
127
128 if (m_name)
129 *s << ", name = \"" << m_name << "\"";
130
131 if (m_symfile_type_sp)
132 {
133 Type *type = m_symfile_type_sp->GetType();
134 if (type)
135 {
136 *s << ", type = {" << type->GetID() << "} " << (void*)type << " (";
137 type->DumpTypeName(s);
138 s->PutChar(')');
139 }
140 }
141
142 if (m_scope != eValueTypeInvalid)
143 {
144 s->PutCString(", scope = ");
145 switch (m_scope)
146 {
147 case eValueTypeVariableGlobal: s->PutCString(m_external ? "global" : "static"); break;
148 case eValueTypeVariableArgument: s->PutCString("parameter"); break;
149 case eValueTypeVariableLocal: s->PutCString("local"); break;
150 default: *s << "??? (" << m_scope << ')';
151 }
152 }
153
154 if (show_context && m_owner_scope != nullptr)
155 {
156 s->PutCString(", context = ( ");
157 m_owner_scope->DumpSymbolContext(s);
158 s->PutCString(" )");
159 }
160
161 bool show_fullpaths = false;
162 m_declaration.Dump(s, show_fullpaths);
163
164 if (m_location.IsValid())
165 {
166 s->PutCString(", location = ");
167 lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
168 if (m_location.IsLocationList())
169 {
170 SymbolContext variable_sc;
171 m_owner_scope->CalculateSymbolContext(&variable_sc);
172 if (variable_sc.function)
173 loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
174 }
175 ABI *abi = nullptr;
176 if (m_owner_scope)
177 {
178 ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
179 if (module_sp)
180 abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
181 }
182 m_location.GetDescription(s, lldb::eDescriptionLevelBrief, loclist_base_addr, abi);
183 }
184
185 if (m_external)
186 s->PutCString(", external");
187
188 if (m_artificial)
189 s->PutCString(", artificial");
190
191 s->EOL();
192 }
193
194 bool
DumpDeclaration(Stream * s,bool show_fullpaths,bool show_module)195 Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
196 {
197 bool dumped_declaration_info = false;
198 if (m_owner_scope)
199 {
200 SymbolContext sc;
201 m_owner_scope->CalculateSymbolContext(&sc);
202 sc.block = nullptr;
203 sc.line_entry.Clear();
204 bool show_inlined_frames = false;
205 const bool show_function_arguments = true;
206 const bool show_function_name = true;
207
208 dumped_declaration_info = sc.DumpStopContext (s,
209 nullptr,
210 Address(),
211 show_fullpaths,
212 show_module,
213 show_inlined_frames,
214 show_function_arguments,
215 show_function_name);
216
217 if (sc.function)
218 s->PutChar(':');
219 }
220 if (m_declaration.DumpStopContext (s, false))
221 dumped_declaration_info = true;
222 return dumped_declaration_info;
223 }
224
225 size_t
MemorySize() const226 Variable::MemorySize() const
227 {
228 return sizeof(Variable);
229 }
230
231
232 void
CalculateSymbolContext(SymbolContext * sc)233 Variable::CalculateSymbolContext (SymbolContext *sc)
234 {
235 if (m_owner_scope)
236 {
237 m_owner_scope->CalculateSymbolContext(sc);
238 sc->variable = this;
239 }
240 else
241 sc->Clear(false);
242 }
243
244 bool
LocationIsValidForFrame(StackFrame * frame)245 Variable::LocationIsValidForFrame (StackFrame *frame)
246 {
247 // Is the variable is described by a single location?
248 if (!m_location.IsLocationList())
249 {
250 // Yes it is, the location is valid.
251 return true;
252 }
253
254 if (frame)
255 {
256 Function *function = frame->GetSymbolContext(eSymbolContextFunction).function;
257 if (function)
258 {
259 TargetSP target_sp (frame->CalculateTarget());
260
261 addr_t loclist_base_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress (target_sp.get());
262 if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
263 return false;
264 // It is a location list. We just need to tell if the location
265 // list contains the current address when converted to a load
266 // address
267 return m_location.LocationListContainsAddress (loclist_base_load_addr,
268 frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get()));
269 }
270 }
271 return false;
272 }
273
274 bool
LocationIsValidForAddress(const Address & address)275 Variable::LocationIsValidForAddress (const Address &address)
276 {
277 // Be sure to resolve the address to section offset prior to
278 // calling this function.
279 if (address.IsSectionOffset())
280 {
281 SymbolContext sc;
282 CalculateSymbolContext(&sc);
283 if (sc.module_sp == address.GetModule())
284 {
285 // Is the variable is described by a single location?
286 if (!m_location.IsLocationList())
287 {
288 // Yes it is, the location is valid.
289 return true;
290 }
291
292 if (sc.function)
293 {
294 addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
295 if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
296 return false;
297 // It is a location list. We just need to tell if the location
298 // list contains the current address when converted to a load
299 // address
300 return m_location.LocationListContainsAddress (loclist_base_file_addr,
301 address.GetFileAddress());
302 }
303 }
304 }
305 return false;
306 }
307
308 bool
IsInScope(StackFrame * frame)309 Variable::IsInScope (StackFrame *frame)
310 {
311 switch (m_scope)
312 {
313 case eValueTypeRegister:
314 case eValueTypeRegisterSet:
315 return frame != nullptr;
316
317 case eValueTypeConstResult:
318 case eValueTypeVariableGlobal:
319 case eValueTypeVariableStatic:
320 return true;
321
322 case eValueTypeVariableArgument:
323 case eValueTypeVariableLocal:
324 if (frame)
325 {
326 // We don't have a location list, we just need to see if the block
327 // that this variable was defined in is currently
328 Block *deepest_frame_block = frame->GetSymbolContext(eSymbolContextBlock).block;
329 if (deepest_frame_block)
330 {
331 SymbolContext variable_sc;
332 CalculateSymbolContext (&variable_sc);
333 // Check for static or global variable defined at the compile unit
334 // level that wasn't defined in a block
335 if (variable_sc.block == nullptr)
336 return true;
337
338 if (variable_sc.block == deepest_frame_block)
339 return true;
340 return variable_sc.block->Contains (deepest_frame_block);
341 }
342 }
343 break;
344
345 default:
346 break;
347 }
348 return false;
349 }
350
351 Error
GetValuesForVariableExpressionPath(const char * variable_expr_path,ExecutionContextScope * scope,GetVariableCallback callback,void * baton,VariableList & variable_list,ValueObjectList & valobj_list)352 Variable::GetValuesForVariableExpressionPath (const char *variable_expr_path,
353 ExecutionContextScope *scope,
354 GetVariableCallback callback,
355 void *baton,
356 VariableList &variable_list,
357 ValueObjectList &valobj_list)
358 {
359 Error error;
360 if (variable_expr_path && callback)
361 {
362 switch (variable_expr_path[0])
363 {
364 case '*':
365 {
366 error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
367 scope,
368 callback,
369 baton,
370 variable_list,
371 valobj_list);
372 if (error.Success())
373 {
374 for (uint32_t i=0; i<valobj_list.GetSize(); )
375 {
376 Error tmp_error;
377 ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
378 if (tmp_error.Fail())
379 {
380 variable_list.RemoveVariableAtIndex (i);
381 valobj_list.RemoveValueObjectAtIndex (i);
382 }
383 else
384 {
385 valobj_list.SetValueObjectAtIndex (i, valobj_sp);
386 ++i;
387 }
388 }
389 }
390 else
391 {
392 error.SetErrorString ("unknown error");
393 }
394 return error;
395 }
396 break;
397
398 case '&':
399 {
400 error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
401 scope,
402 callback,
403 baton,
404 variable_list,
405 valobj_list);
406 if (error.Success())
407 {
408 for (uint32_t i=0; i<valobj_list.GetSize(); )
409 {
410 Error tmp_error;
411 ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
412 if (tmp_error.Fail())
413 {
414 variable_list.RemoveVariableAtIndex (i);
415 valobj_list.RemoveValueObjectAtIndex (i);
416 }
417 else
418 {
419 valobj_list.SetValueObjectAtIndex (i, valobj_sp);
420 ++i;
421 }
422 }
423 }
424 else
425 {
426 error.SetErrorString ("unknown error");
427 }
428 return error;
429 }
430 break;
431
432 default:
433 {
434 static RegularExpression g_regex ("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)");
435 RegularExpression::Match regex_match(1);
436 if (g_regex.Execute(variable_expr_path, ®ex_match))
437 {
438 std::string variable_name;
439 if (regex_match.GetMatchAtIndex(variable_expr_path, 1, variable_name))
440 {
441 variable_list.Clear();
442 if (callback (baton, variable_name.c_str(), variable_list))
443 {
444 uint32_t i=0;
445 while (i < variable_list.GetSize())
446 {
447 VariableSP var_sp (variable_list.GetVariableAtIndex (i));
448 ValueObjectSP valobj_sp;
449 if (var_sp)
450 {
451 ValueObjectSP variable_valobj_sp(ValueObjectVariable::Create (scope, var_sp));
452 if (variable_valobj_sp)
453 {
454 const char *variable_sub_expr_path = variable_expr_path + variable_name.size();
455 if (*variable_sub_expr_path)
456 {
457 const char* first_unparsed = nullptr;
458 ValueObject::ExpressionPathScanEndReason reason_to_stop;
459 ValueObject::ExpressionPathEndResultType final_value_type;
460 ValueObject::GetValueForExpressionPathOptions options;
461 ValueObject::ExpressionPathAftermath final_task_on_target;
462
463 valobj_sp = variable_valobj_sp->GetValueForExpressionPath (variable_sub_expr_path,
464 &first_unparsed,
465 &reason_to_stop,
466 &final_value_type,
467 options,
468 &final_task_on_target);
469 if (!valobj_sp)
470 {
471 error.SetErrorStringWithFormat ("invalid expression path '%s' for variable '%s'",
472 variable_sub_expr_path,
473 var_sp->GetName().GetCString());
474 }
475 }
476 else
477 {
478 // Just the name of a variable with no extras
479 valobj_sp = variable_valobj_sp;
480 }
481 }
482 }
483
484 if (!var_sp || !valobj_sp)
485 {
486 variable_list.RemoveVariableAtIndex (i);
487 }
488 else
489 {
490 valobj_list.Append(valobj_sp);
491 ++i;
492 }
493 }
494
495 if (variable_list.GetSize() > 0)
496 {
497 error.Clear();
498 return error;
499 }
500 }
501 }
502 }
503 error.SetErrorStringWithFormat ("unable to extract a variable name from '%s'", variable_expr_path);
504 }
505 break;
506 }
507 }
508 error.SetErrorString ("unknown error");
509 return error;
510 }
511
512 bool
DumpLocationForAddress(Stream * s,const Address & address)513 Variable::DumpLocationForAddress (Stream *s, const Address &address)
514 {
515 // Be sure to resolve the address to section offset prior to
516 // calling this function.
517 if (address.IsSectionOffset())
518 {
519 SymbolContext sc;
520 CalculateSymbolContext(&sc);
521 if (sc.module_sp == address.GetModule())
522 {
523 ABI *abi = nullptr;
524 if (m_owner_scope)
525 {
526 ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
527 if (module_sp)
528 abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
529 }
530
531 const addr_t file_addr = address.GetFileAddress();
532 if (sc.function)
533 {
534 if (sc.function->GetAddressRange().ContainsFileAddress(address))
535 {
536 addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
537 if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
538 return false;
539 return m_location.DumpLocationForAddress (s,
540 eDescriptionLevelBrief,
541 loclist_base_file_addr,
542 file_addr,
543 abi);
544 }
545 }
546 return m_location.DumpLocationForAddress (s,
547 eDescriptionLevelBrief,
548 LLDB_INVALID_ADDRESS,
549 file_addr,
550 abi);
551 }
552 }
553 return false;
554 }
555
556
557 static void
558 PrivateAutoComplete (StackFrame *frame,
559 const std::string &partial_path,
560 const std::string &prefix_path, // Anything that has been resolved already will be in here
561 const ClangASTType& clang_type,
562 StringList &matches,
563 bool &word_complete);
564
565 static void
566 PrivateAutoCompleteMembers (StackFrame *frame,
567 const std::string &partial_member_name,
568 const std::string &partial_path,
569 const std::string &prefix_path, // Anything that has been resolved already will be in here
570 const ClangASTType& clang_type,
571 StringList &matches,
572 bool &word_complete);
573
574 static void
PrivateAutoCompleteMembers(StackFrame * frame,const std::string & partial_member_name,const std::string & partial_path,const std::string & prefix_path,const ClangASTType & clang_type,StringList & matches,bool & word_complete)575 PrivateAutoCompleteMembers (StackFrame *frame,
576 const std::string &partial_member_name,
577 const std::string &partial_path,
578 const std::string &prefix_path, // Anything that has been resolved already will be in here
579 const ClangASTType& clang_type,
580 StringList &matches,
581 bool &word_complete)
582 {
583
584 // We are in a type parsing child members
585 const uint32_t num_bases = clang_type.GetNumDirectBaseClasses();
586
587 if (num_bases > 0)
588 {
589 for (uint32_t i = 0; i < num_bases; ++i)
590 {
591 ClangASTType base_class_type (clang_type.GetDirectBaseClassAtIndex (i, nullptr));
592
593 PrivateAutoCompleteMembers (frame,
594 partial_member_name,
595 partial_path,
596 prefix_path,
597 base_class_type.GetCanonicalType(),
598 matches,
599 word_complete);
600 }
601 }
602
603 const uint32_t num_vbases = clang_type.GetNumVirtualBaseClasses();
604
605 if (num_vbases > 0)
606 {
607 for (uint32_t i = 0; i < num_vbases; ++i)
608 {
609 ClangASTType vbase_class_type (clang_type.GetVirtualBaseClassAtIndex(i,nullptr));
610
611 PrivateAutoCompleteMembers (frame,
612 partial_member_name,
613 partial_path,
614 prefix_path,
615 vbase_class_type.GetCanonicalType(),
616 matches,
617 word_complete);
618 }
619 }
620
621 // We are in a type parsing child members
622 const uint32_t num_fields = clang_type.GetNumFields();
623
624 if (num_fields > 0)
625 {
626 for (uint32_t i = 0; i < num_fields; ++i)
627 {
628 std::string member_name;
629
630 ClangASTType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, nullptr, nullptr, nullptr);
631
632 if (partial_member_name.empty() ||
633 member_name.find(partial_member_name) == 0)
634 {
635 if (member_name == partial_member_name)
636 {
637 PrivateAutoComplete (frame,
638 partial_path,
639 prefix_path + member_name, // Anything that has been resolved already will be in here
640 member_clang_type.GetCanonicalType(),
641 matches,
642 word_complete);
643 }
644 else
645 {
646 matches.AppendString (prefix_path + member_name);
647 }
648 }
649 }
650 }
651 }
652
653 static void
PrivateAutoComplete(StackFrame * frame,const std::string & partial_path,const std::string & prefix_path,const ClangASTType & clang_type,StringList & matches,bool & word_complete)654 PrivateAutoComplete (StackFrame *frame,
655 const std::string &partial_path,
656 const std::string &prefix_path, // Anything that has been resolved already will be in here
657 const ClangASTType& clang_type,
658 StringList &matches,
659 bool &word_complete)
660 {
661 // printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str());
662 std::string remaining_partial_path;
663
664 const lldb::TypeClass type_class = clang_type.GetTypeClass();
665 if (partial_path.empty())
666 {
667 if (clang_type.IsValid())
668 {
669 switch (type_class)
670 {
671 default:
672 case eTypeClassArray:
673 case eTypeClassBlockPointer:
674 case eTypeClassBuiltin:
675 case eTypeClassComplexFloat:
676 case eTypeClassComplexInteger:
677 case eTypeClassEnumeration:
678 case eTypeClassFunction:
679 case eTypeClassMemberPointer:
680 case eTypeClassReference:
681 case eTypeClassTypedef:
682 case eTypeClassVector:
683 {
684 matches.AppendString (prefix_path);
685 word_complete = matches.GetSize() == 1;
686 }
687 break;
688
689 case eTypeClassClass:
690 case eTypeClassStruct:
691 case eTypeClassUnion:
692 if (prefix_path.back() != '.')
693 matches.AppendString (prefix_path + '.');
694 break;
695
696 case eTypeClassObjCObject:
697 case eTypeClassObjCInterface:
698 break;
699 case eTypeClassObjCObjectPointer:
700 case eTypeClassPointer:
701 {
702 bool omit_empty_base_classes = true;
703 if (clang_type.GetNumChildren (omit_empty_base_classes) > 0)
704 matches.AppendString (prefix_path + "->");
705 else
706 {
707 matches.AppendString (prefix_path);
708 word_complete = true;
709 }
710 }
711 break;
712 }
713 }
714 else
715 {
716 if (frame)
717 {
718 const bool get_file_globals = true;
719
720 VariableList *variable_list = frame->GetVariableList(get_file_globals);
721
722 if (variable_list)
723 {
724 const size_t num_variables = variable_list->GetSize();
725 for (size_t i=0; i<num_variables; ++i)
726 {
727 Variable *variable = variable_list->GetVariableAtIndex(i).get();
728 matches.AppendString (variable->GetName().AsCString());
729 }
730 }
731 }
732 }
733 }
734 else
735 {
736 const char ch = partial_path[0];
737 switch (ch)
738 {
739 case '*':
740 if (prefix_path.empty())
741 {
742 PrivateAutoComplete (frame,
743 partial_path.substr(1),
744 std::string("*"),
745 clang_type,
746 matches,
747 word_complete);
748 }
749 break;
750
751 case '&':
752 if (prefix_path.empty())
753 {
754 PrivateAutoComplete (frame,
755 partial_path.substr(1),
756 std::string("&"),
757 clang_type,
758 matches,
759 word_complete);
760 }
761 break;
762
763 case '-':
764 if (partial_path[1] == '>' && !prefix_path.empty())
765 {
766 switch (type_class)
767 {
768 case lldb::eTypeClassPointer:
769 {
770 ClangASTType pointee_type(clang_type.GetPointeeType());
771 if (partial_path[2])
772 {
773 // If there is more after the "->", then search deeper
774 PrivateAutoComplete (frame,
775 partial_path.substr(2),
776 prefix_path + "->",
777 pointee_type.GetCanonicalType(),
778 matches,
779 word_complete);
780 }
781 else
782 {
783 // Nothing after the "->", so list all members
784 PrivateAutoCompleteMembers (frame,
785 std::string(),
786 std::string(),
787 prefix_path + "->",
788 pointee_type.GetCanonicalType(),
789 matches,
790 word_complete);
791 }
792 }
793 default:
794 break;
795 }
796 }
797 break;
798
799 case '.':
800 if (clang_type.IsValid())
801 {
802 switch (type_class)
803 {
804 case lldb::eTypeClassUnion:
805 case lldb::eTypeClassStruct:
806 case lldb::eTypeClassClass:
807 if (partial_path[1])
808 {
809 // If there is more after the ".", then search deeper
810 PrivateAutoComplete (frame,
811 partial_path.substr(1),
812 prefix_path + ".",
813 clang_type,
814 matches,
815 word_complete);
816
817 }
818 else
819 {
820 // Nothing after the ".", so list all members
821 PrivateAutoCompleteMembers (frame,
822 std::string(),
823 partial_path,
824 prefix_path + ".",
825 clang_type,
826 matches,
827 word_complete);
828 }
829 default:
830 break;
831 }
832 }
833 break;
834 default:
835 if (isalpha(ch) || ch == '_' || ch == '$')
836 {
837 const size_t partial_path_len = partial_path.size();
838 size_t pos = 1;
839 while (pos < partial_path_len)
840 {
841 const char curr_ch = partial_path[pos];
842 if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$')
843 {
844 ++pos;
845 continue;
846 }
847 break;
848 }
849
850 std::string token(partial_path, 0, pos);
851 remaining_partial_path = partial_path.substr(pos);
852
853 if (clang_type.IsValid())
854 {
855 PrivateAutoCompleteMembers (frame,
856 token,
857 remaining_partial_path,
858 prefix_path,
859 clang_type,
860 matches,
861 word_complete);
862 }
863 else if (frame)
864 {
865 // We haven't found our variable yet
866 const bool get_file_globals = true;
867
868 VariableList *variable_list = frame->GetVariableList(get_file_globals);
869
870 if (!variable_list)
871 break;
872
873 const size_t num_variables = variable_list->GetSize();
874 for (size_t i=0; i<num_variables; ++i)
875 {
876 Variable *variable = variable_list->GetVariableAtIndex(i).get();
877
878 if (!variable)
879 continue;
880
881 const char *variable_name = variable->GetName().AsCString();
882 if (strstr(variable_name, token.c_str()) == variable_name)
883 {
884 if (strcmp (variable_name, token.c_str()) == 0)
885 {
886 Type *variable_type = variable->GetType();
887 if (variable_type)
888 {
889 ClangASTType variable_clang_type (variable_type->GetClangForwardType());
890 PrivateAutoComplete (frame,
891 remaining_partial_path,
892 prefix_path + token, // Anything that has been resolved already will be in here
893 variable_clang_type.GetCanonicalType(),
894 matches,
895 word_complete);
896 }
897 else
898 {
899 matches.AppendString (prefix_path + variable_name);
900 }
901 }
902 else if (remaining_partial_path.empty())
903 {
904 matches.AppendString (prefix_path + variable_name);
905 }
906 }
907 }
908 }
909 }
910 break;
911 }
912 }
913 }
914
915
916
917 size_t
AutoComplete(const ExecutionContext & exe_ctx,const char * partial_path_cstr,StringList & matches,bool & word_complete)918 Variable::AutoComplete (const ExecutionContext &exe_ctx,
919 const char *partial_path_cstr,
920 StringList &matches,
921 bool &word_complete)
922 {
923 word_complete = false;
924 std::string partial_path;
925 std::string prefix_path;
926 ClangASTType clang_type;
927 if (partial_path_cstr && partial_path_cstr[0])
928 partial_path = partial_path_cstr;
929
930 PrivateAutoComplete (exe_ctx.GetFramePtr(),
931 partial_path,
932 prefix_path,
933 clang_type,
934 matches,
935 word_complete);
936
937 return matches.GetSize();
938 }
939
940