bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type, uint64_t &size) { void *opaque_ptr = compiler_type.GetOpaqueQualType(); size = m_type_size_cache.Lookup(opaque_ptr); // an ObjC object will at least have an ISA, so 0 is definitely not OK if (size > 0) return true; ClassDescriptorSP class_descriptor_sp = GetClassDescriptorFromClassName(compiler_type.GetTypeName()); if (!class_descriptor_sp) return false; int32_t max_offset = INT32_MIN; uint64_t sizeof_max = 0; bool found = false; for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) { const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx); int32_t cur_offset = ivar.m_offset; if (cur_offset > max_offset) { max_offset = cur_offset; sizeof_max = ivar.m_size; found = true; } } size = 8 * (max_offset + sizeof_max); if (found) m_type_size_cache.Insert(opaque_ptr, size); return found; }
bool ClangUtil::IsClangType(const CompilerType &ct) { if (llvm::dyn_cast_or_null<ClangASTContext>(ct.GetTypeSystem()) == nullptr) return false; if (!ct.GetOpaqueQualType()) return false; return true; }
CompilerType GoUserExpression::GoInterpreter::EvaluateType(const GoASTExpr *e) { TargetSP target = m_exe_ctx.GetTargetSP(); if (auto *id = llvm::dyn_cast<GoASTIdent>(e)) { CompilerType result = LookupType(target, ConstString(id->GetName().m_value)); if (result.IsValid()) return result; std::string fullname = (m_package + "." + id->GetName().m_value).str(); result = LookupType(target, ConstString(fullname)); if (!result) m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str()); return result; } if (auto *sel = llvm::dyn_cast<GoASTSelectorExpr>(e)) { std::string package; if (auto *pkg_node = llvm::dyn_cast<GoASTIdent>(sel->GetX())) { package = pkg_node->GetName().m_value.str(); } else if (auto *str_node = llvm::dyn_cast<GoASTBasicLit>(sel->GetX())) { if (str_node->GetValue().m_type == GoLexer::LIT_STRING) { package = str_node->GetValue().m_value.substr(1).str(); package.resize(package.length() - 1); } } if (package.empty()) { m_error.SetErrorStringWithFormat("Invalid %s in type expression", sel->GetX()->GetKindName()); return CompilerType(); } std::string fullname = (package + "." + sel->GetSel()->GetName().m_value).str(); CompilerType result = LookupType(target, ConstString(fullname)); if (!result) m_error.SetErrorStringWithFormat("Unknown type %s", fullname.c_str()); return result; } if (auto *star = llvm::dyn_cast<GoASTStarExpr>(e)) { CompilerType elem = EvaluateType(star->GetX()); return elem.GetPointerType(); } if (auto *paren = llvm::dyn_cast<GoASTParenExpr>(e)) return EvaluateType(paren->GetX()); if (auto *array = llvm::dyn_cast<GoASTArrayType>(e)) { CompilerType elem = EvaluateType(array->GetElt()); } m_error.SetErrorStringWithFormat("Invalid %s in type expression", e->GetKindName()); return CompilerType(); }
uint64_t JavaASTContext::CalculateDynamicTypeId(ExecutionContext *exe_ctx, const CompilerType &type, ValueObject &in_value) { if (JavaObjectType *obj = llvm::dyn_cast<JavaObjectType>( static_cast<JavaType *>(type.GetOpaqueQualType()))) return obj->CalculateDynamicTypeId(exe_ctx, in_value); if (JavaArrayType *arr = llvm::dyn_cast<JavaArrayType>( static_cast<JavaType *>(type.GetOpaqueQualType()))) return arr->CalculateDynamicTypeId(exe_ctx, in_value); return UINT64_MAX; }
bool lldb_private::formatters::swift::SwiftOptionSetSummaryProvider:: WouldEvenConsiderFormatting(CompilerType clang_type) { SwiftASTContext *swift_ast_ctx = llvm::dyn_cast_or_null<SwiftASTContext>(clang_type.GetTypeSystem()); if (!swift_ast_ctx) return false; return clang_type.IsValid() && swift_ast_ctx->IsTrivialOptionSetType(clang_type) && swift_ast_ctx->IsImportedType(clang_type, nullptr); }
void Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) { m_size = type.GetByteSize(nullptr); uint32_t bit_alignment = type.GetTypeBitAlign(); if (bit_alignment % 8) { bit_alignment += 8; bit_alignment &= ~((uint32_t)0x111u); } m_alignment = bit_alignment / 8; }
static lldb::Format GetItemFormatForFormat (lldb::Format format, CompilerType element_type) { switch (format) { case lldb::eFormatVectorOfChar: return lldb::eFormatChar; case lldb::eFormatVectorOfFloat32: case lldb::eFormatVectorOfFloat64: return lldb::eFormatFloat; case lldb::eFormatVectorOfSInt16: case lldb::eFormatVectorOfSInt32: case lldb::eFormatVectorOfSInt64: case lldb::eFormatVectorOfSInt8: return lldb::eFormatDecimal; case lldb::eFormatVectorOfUInt128: case lldb::eFormatVectorOfUInt16: case lldb::eFormatVectorOfUInt32: case lldb::eFormatVectorOfUInt64: case lldb::eFormatVectorOfUInt8: return lldb::eFormatUnsigned; case lldb::eFormatBinary: case lldb::eFormatComplexInteger: case lldb::eFormatDecimal: case lldb::eFormatEnum: case lldb::eFormatInstruction: case lldb::eFormatOSType: case lldb::eFormatVoid: return eFormatHex; case lldb::eFormatDefault: { // special case the (default, char) combination to actually display as an integer value // most often, you won't want to see the ASCII characters... (and if you do, eFormatChar is a keystroke away) bool is_char = element_type.IsCharType(); bool is_signed = false; element_type.IsIntegerType(is_signed); return is_char ? (is_signed ? lldb::eFormatDecimal : eFormatHex) : format; } break; default: return format; } }
QualType ClangUtil::GetQualType(const CompilerType &ct) { // Make sure we have a clang type before making a clang::QualType if (!IsClangType(ct)) return QualType(); return QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); }
ValueObjectSP ABISysV_s390x::GetReturnValueObjectImpl( Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; if (!return_compiler_type) return return_valobj_sp; ExecutionContext exe_ctx(thread.shared_from_this()); return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type); if (return_valobj_sp) return return_valobj_sp; RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); if (!reg_ctx_sp) return return_valobj_sp; if (return_compiler_type.IsAggregateType()) { // FIXME: This is just taking a guess, r2 may very well no longer hold the // return storage location. // If we are going to do this right, when we make a new frame we should // check to see if it uses a memory return, and if we are at the first // instruction and if so stash away the return location. Then we would // only return the memory return value if we know it is valid. unsigned r2_id = reg_ctx_sp->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB]; lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0); return_valobj_sp = ValueObjectMemory::Create( &thread, "", Address(storage_addr, nullptr), return_compiler_type); } return return_valobj_sp; }
void JavaASTContext::CompleteObjectType(const CompilerType &object_type) { JavaObjectType *obj = llvm::dyn_cast<JavaObjectType>( static_cast<JavaType *>(object_type.GetOpaqueQualType())); assert(obj && "JavaASTContext::CompleteObjectType called with not a JavaObjectType"); obj->SetCompleteType(true); }
uint32_t JavaASTContext::CalculateArraySize(const CompilerType &type, ValueObject &in_value) { if (JavaArrayType *arr = llvm::dyn_cast<JavaArrayType>( static_cast<JavaType *>(type.GetOpaqueQualType()))) return arr->GetNumElements(&in_value); return UINT32_MAX; }
ValueObjectSP ABISysV_i386::GetReturnValueObjectImpl (Thread &thread, CompilerType &return_clang_type) const { ValueObjectSP return_valobj_sp; if (!return_clang_type) return return_valobj_sp; ExecutionContext exe_ctx (thread.shared_from_this()); return_valobj_sp = GetReturnValueObjectSimple(thread, return_clang_type); if (return_valobj_sp) return return_valobj_sp; RegisterContextSP reg_ctx_sp = thread.GetRegisterContext(); if (!reg_ctx_sp) return return_valobj_sp; if (return_clang_type.IsAggregateType()) { unsigned eax_id = reg_ctx_sp->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB]; lldb::addr_t storage_addr = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff); return_valobj_sp = ValueObjectMemory::Create (&thread, "", Address (storage_addr, nullptr), return_clang_type); } return return_valobj_sp; }
uint64_t JavaASTContext::CalculateArrayElementOffset(const CompilerType &type, size_t index) { if (JavaArrayType *arr = llvm::dyn_cast<JavaArrayType>( static_cast<JavaType *>(type.GetOpaqueQualType()))) return arr->GetElementOffset(index); return UINT64_MAX; }
void compile_multiple(CompilerType& compiler, std::function<std::pair<std::string, ValueType>(std::string)> parser, std::vector<std::string>& inputs) { boost::iostreams::filtering_istream input_stream; std::string line; for (auto input_as_string : inputs) { auto input = boost::filesystem::path(input_as_string); if(boost::filesystem::is_directory(input)) { int files_added = 0; for(auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(input), {})) { if (entry.path().extension() == ".gz") { input_stream.push(boost::iostreams::gzip_decompressor()); } boost::iostreams::file_source file(entry.path().string(), std::ios_base::in | std::ios_base::binary); input_stream.push(file); ++files_added; while (std::getline(input_stream, line)) { auto parse_result = parser(line); if (parse_result.first.size() == 0) { continue; } compiler.Add(parse_result.first, parse_result.second); } input_stream.reset(); } } else { if (input.extension() == ".gz"){ input_stream.push(boost::iostreams::gzip_decompressor()); } boost::iostreams::file_source file(input.string(), std::ios_base::in | std::ios_base::binary); input_stream.push(file); while (std::getline(input_stream, line)) { auto parse_result = parser(line); compiler.Add(parse_result.first, parse_result.second); } input_stream.reset(); } } }
static size_t CalculateNumChildren (CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope = nullptr // does not matter here because all we trade in are basic types ) { auto container_size = container_type.GetByteSize(exe_scope); auto element_size = element_type.GetByteSize(exe_scope); if (element_size) { if (container_size % element_size) return 0; return container_size / element_size; } return 0; }
static bool IsPointerValue (const CompilerType &type) { Flags type_flags(type.GetTypeInfo()); if (type_flags.AnySet(eTypeIsPointer)) return type_flags.AllClear(eTypeIsBuiltIn); return false; }
CompilerType ClangUtil::RemoveFastQualifiers(const CompilerType &ct) { if (!IsClangType(ct)) return ct; QualType qual_type(GetQualType(ct)); qual_type.removeLocalFastQualifiers(); return CompilerType(ct.GetTypeSystem(), qual_type.getAsOpaquePtr()); }
void JavaASTContext::SetDynamicTypeId(const CompilerType &type, const DWARFExpression &type_id) { JavaObjectType *obj = llvm::dyn_cast<JavaObjectType>( static_cast<JavaType *>(type.GetOpaqueQualType())); assert(obj && "JavaASTContext::SetDynamicTypeId called with not a JavaObjectType"); obj->SetDynamicTypeId(type_id); }
void JavaASTContext::AddBaseClassToObject(const CompilerType &object_type, const CompilerType &member_type, uint32_t member_offset) { JavaObjectType *obj = llvm::dyn_cast<JavaObjectType>( static_cast<JavaType *>(object_type.GetOpaqueQualType())); assert(obj && "JavaASTContext::AddMemberToObject called with not a JavaObjectType"); obj->AddBaseClass(member_type, member_offset); }
CompilerType ClangASTImporter::CopyType(ClangASTContext &dst_ast, const CompilerType &src_type) { clang::ASTContext *dst_clang_ast = dst_ast.getASTContext(); if (dst_clang_ast) { ClangASTContext *src_ast = llvm::dyn_cast_or_null<ClangASTContext>(src_type.GetTypeSystem()); if (src_ast) { clang::ASTContext *src_clang_ast = src_ast->getASTContext(); if (src_clang_ast) { lldb::opaque_compiler_type_t dst_clang_type = CopyType( dst_clang_ast, src_clang_ast, src_type.GetOpaqueQualType()); if (dst_clang_type) return CompilerType(&dst_ast, dst_clang_type); } } } return CompilerType(); }
CompilerType JavaASTContext::CreateReferenceType(const CompilerType &pointee_type) { ConstString name = pointee_type.GetTypeName(); auto it = m_reference_type_map.find(name); if (it == m_reference_type_map.end()) it = m_reference_type_map .emplace(name, std::unique_ptr<JavaType>( new JavaReferenceType(pointee_type))) .first; return CompilerType(this, it->second.get()); }
CompilerType JavaASTContext::CreateArrayType( const ConstString &linkage_name, const CompilerType &element_type, const DWARFExpression &length_expression, const lldb::addr_t data_offset) { ConstString name = element_type.GetTypeName(); auto it = m_array_type_map.find(name); if (it == m_array_type_map.end()) { std::unique_ptr<JavaType> array_type(new JavaArrayType( linkage_name, element_type, length_expression, data_offset)); it = m_array_type_map.emplace(name, std::move(array_type)).first; } return CompilerType(this, it->second.get()); }
bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { if (!CanImport(compiler_type)) return false; if (Import(compiler_type)) { ClangASTContext::CompleteTagDeclarationDefinition(compiler_type); return true; } ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(), false); return false; }
ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) { if (idx >= m_elements.size() || !m_first) return ValueObjectSP(); if (m_elements[idx]) return m_elements[idx]; ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false); CompilerType type; ValueObjectSP chunk; // For small bitsets __first_ is not an array, but a plain size_t. if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) { llvm::Optional<uint64_t> bit_size = type.GetBitSize(ctx.GetBestExecutionContextScope()); if (!bit_size || *bit_size == 0) return {}; chunk = m_first->GetChildAtIndex(idx / *bit_size, true); } else { type = m_first->GetCompilerType(); chunk = m_first; } if (!type || !chunk) return {}; llvm::Optional<uint64_t> bit_size = type.GetBitSize(ctx.GetBestExecutionContextScope()); if (!bit_size || *bit_size == 0) return {}; size_t chunk_idx = idx % *bit_size; uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx)); DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size); m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data, ctx, m_bool_type); return m_elements[idx]; }
void finalize_compile(CompilerType& compiler, std::string& output, size_t partition_size = 0) { if (partition_size == 0) { std::ofstream out_stream(output, std::ios::binary); compiler.Compile(callback); compiler.Write(out_stream); out_stream.close(); } else { std::string output_part_zero = output + ".0"; int partition_number = 1; std::ofstream out_stream(output_part_zero, std::ios::binary); while (compiler.CompileNext(partition_size, out_stream, 2, callback)) { std::cout << "Finalize partition " << partition_number << std::endl; out_stream.close(); out_stream.open(output + "." + std::to_string(partition_number), std::ios::binary); ++partition_number; } out_stream.close(); } }
uint32_t GoASTContext::GetNumChildren(lldb::opaque_compiler_type_t type, bool omit_empty_base_classes) { if (!type || !GetCompleteType(type)) return 0; GoType *t = static_cast<GoType *>(type); if (t->GetGoKind() == GoType::KIND_PTR) { CompilerType elem = t->GetElementType(); if (elem.IsAggregateType()) return elem.GetNumChildren(omit_empty_base_classes); return 1; } else if (GoArray *array = t->GetArray()) { return array->GetLength(); } else if (t->IsTypedef()) { return t->GetElementType().GetNumChildren(omit_empty_base_classes); } return GetNumFields(type); }
ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, bool persistent) const { if (!ast_type.IsValid()) return ValueObjectSP(); ValueObjectSP return_valobj_sp; return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type); if (!return_valobj_sp) return return_valobj_sp; // Now turn this into a persistent variable. // FIXME: This code is duplicated from Target::EvaluateExpression, and it is // used in similar form in a couple // of other places. Figure out the correct Create function to do all this // work. if (persistent) { PersistentExpressionState *persistent_expression_state = thread.CalculateTarget()->GetPersistentExpressionStateForLanguage( ast_type.GetMinimumLanguage()); if (!persistent_expression_state) return ValueObjectSP(); ConstString persistent_variable_name( persistent_expression_state->GetNextPersistentVariableName()); lldb::ValueObjectSP const_valobj_sp; // Check in case our value is already a constant value if (return_valobj_sp->GetIsConstant()) { const_valobj_sp = return_valobj_sp; const_valobj_sp->SetName(persistent_variable_name); } else const_valobj_sp = return_valobj_sp->CreateConstantValue(persistent_variable_name); lldb::ValueObjectSP live_valobj_sp = return_valobj_sp; return_valobj_sp = const_valobj_sp; ExpressionVariableSP clang_expr_variable_sp( persistent_expression_state->CreatePersistentVariable( return_valobj_sp)); assert(clang_expr_variable_sp); // Set flags and live data as appropriate const Value &result_value = live_valobj_sp->GetValue(); switch (result_value.GetValueType()) { case Value::eValueTypeHostAddress: case Value::eValueTypeFileAddress: // we don't do anything with these for now break; case Value::eValueTypeScalar: case Value::eValueTypeVector: clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsFreezeDried; clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation; break; case Value::eValueTypeLoadAddress: clang_expr_variable_sp->m_live_sp = live_valobj_sp; clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference; break; } return_valobj_sp = clang_expr_variable_sp->GetValueObject(); } return return_valobj_sp; }
ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl (Thread &thread, CompilerType &return_clang_type) const { ValueObjectSP return_valobj_sp; Value value; if (!return_clang_type) return return_valobj_sp; ExecutionContext exe_ctx (thread.shared_from_this()); if (exe_ctx.GetTargetPtr() == NULL || exe_ctx.GetProcessPtr() == NULL) return return_valobj_sp; value.SetCompilerType(return_clang_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; bool is_signed = false; bool is_complex = false; uint32_t count = 0; // In MIPS register "r2" (v0) holds the integer function return values const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0); size_t bit_width = return_clang_type.GetBitSize(&thread); if (return_clang_type.IsIntegerType (is_signed)) { switch (bit_width) { default: return return_valobj_sp; case 64: { const RegisterInfo *r3_reg_info = reg_ctx->GetRegisterInfoByName("r3", 0); uint64_t raw_value; raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX; raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0) & UINT32_MAX)) << 32; if (is_signed) value.GetScalar() = (int64_t)raw_value; else value.GetScalar() = (uint64_t)raw_value; } break; case 32: if (is_signed) value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX); else value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX); break; case 16: if (is_signed) value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX); else value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX); break; case 8: if (is_signed) value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX); else value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX); break; } } else if (return_clang_type.IsPointerType ()) { uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX; value.GetScalar() = ptr; } else if (return_clang_type.IsAggregateType ()) { // Structure/Vector is always passed in memory and pointer to that memory is passed in r2. uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r2", 0), 0); // We have got the address. Create a memory object out of it return_valobj_sp = ValueObjectMemory::Create (&thread, "", Address (mem_address, NULL), return_clang_type); return return_valobj_sp; } else if (return_clang_type.IsFloatingPointType (count, is_complex)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); if (count == 1 && !is_complex) { switch (bit_width) { default: return return_valobj_sp; case 64: { static_assert(sizeof(double) == sizeof(uint64_t), ""); uint64_t raw_value; raw_value = reg_ctx->ReadRegisterAsUnsigned(f0_info, 0) & UINT32_MAX; raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(f1_info, 0) & UINT32_MAX)) << 32; value.GetScalar() = *reinterpret_cast<double*>(&raw_value); break; } case 32: { static_assert(sizeof(float) == sizeof(uint32_t), ""); uint32_t raw_value = reg_ctx->ReadRegisterAsUnsigned(f0_info, 0) & UINT32_MAX; value.GetScalar() = *reinterpret_cast<float*>(&raw_value); break; } } } else { // not handled yet return return_valobj_sp; } } else { // not handled yet return return_valobj_sp; } // If we get here, we have a valid Value, so make our ValueObject out of it: return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); return return_valobj_sp; }
static void PrivateAutoComplete (StackFrame *frame, const std::string &partial_path, const std::string &prefix_path, // Anything that has been resolved already will be in here const CompilerType& compiler_type, StringList &matches, bool &word_complete) { // printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str()); std::string remaining_partial_path; const lldb::TypeClass type_class = compiler_type.GetTypeClass(); if (partial_path.empty()) { if (compiler_type.IsValid()) { switch (type_class) { default: case eTypeClassArray: case eTypeClassBlockPointer: case eTypeClassBuiltin: case eTypeClassComplexFloat: case eTypeClassComplexInteger: case eTypeClassEnumeration: case eTypeClassFunction: case eTypeClassMemberPointer: case eTypeClassReference: case eTypeClassTypedef: case eTypeClassVector: { matches.AppendString (prefix_path); word_complete = matches.GetSize() == 1; } break; case eTypeClassClass: case eTypeClassStruct: case eTypeClassUnion: if (prefix_path.back() != '.') matches.AppendString (prefix_path + '.'); break; case eTypeClassObjCObject: case eTypeClassObjCInterface: break; case eTypeClassObjCObjectPointer: case eTypeClassPointer: { bool omit_empty_base_classes = true; if (compiler_type.GetNumChildren (omit_empty_base_classes) > 0) matches.AppendString (prefix_path + "->"); else { matches.AppendString (prefix_path); word_complete = true; } } break; } } else { if (frame) { const bool get_file_globals = true; VariableList *variable_list = frame->GetVariableList(get_file_globals); if (variable_list) { const size_t num_variables = variable_list->GetSize(); for (size_t i=0; i<num_variables; ++i) { Variable *variable = variable_list->GetVariableAtIndex(i).get(); matches.AppendString (variable->GetName().AsCString()); } } } } } else { const char ch = partial_path[0]; switch (ch) { case '*': if (prefix_path.empty()) { PrivateAutoComplete (frame, partial_path.substr(1), std::string("*"), compiler_type, matches, word_complete); } break; case '&': if (prefix_path.empty()) { PrivateAutoComplete (frame, partial_path.substr(1), std::string("&"), compiler_type, matches, word_complete); } break; case '-': if (partial_path[1] == '>' && !prefix_path.empty()) { switch (type_class) { case lldb::eTypeClassPointer: { CompilerType pointee_type(compiler_type.GetPointeeType()); if (partial_path[2]) { // If there is more after the "->", then search deeper PrivateAutoComplete (frame, partial_path.substr(2), prefix_path + "->", pointee_type.GetCanonicalType(), matches, word_complete); } else { // Nothing after the "->", so list all members PrivateAutoCompleteMembers (frame, std::string(), std::string(), prefix_path + "->", pointee_type.GetCanonicalType(), matches, word_complete); } } break; default: break; } } break; case '.': if (compiler_type.IsValid()) { switch (type_class) { case lldb::eTypeClassUnion: case lldb::eTypeClassStruct: case lldb::eTypeClassClass: if (partial_path[1]) { // If there is more after the ".", then search deeper PrivateAutoComplete (frame, partial_path.substr(1), prefix_path + ".", compiler_type, matches, word_complete); } else { // Nothing after the ".", so list all members PrivateAutoCompleteMembers (frame, std::string(), partial_path, prefix_path + ".", compiler_type, matches, word_complete); } break; default: break; } } break; default: if (isalpha(ch) || ch == '_' || ch == '$') { const size_t partial_path_len = partial_path.size(); size_t pos = 1; while (pos < partial_path_len) { const char curr_ch = partial_path[pos]; if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$') { ++pos; continue; } break; } std::string token(partial_path, 0, pos); remaining_partial_path = partial_path.substr(pos); if (compiler_type.IsValid()) { PrivateAutoCompleteMembers (frame, token, remaining_partial_path, prefix_path, compiler_type, matches, word_complete); } else if (frame) { // We haven't found our variable yet const bool get_file_globals = true; VariableList *variable_list = frame->GetVariableList(get_file_globals); if (!variable_list) break; const size_t num_variables = variable_list->GetSize(); for (size_t i=0; i<num_variables; ++i) { Variable *variable = variable_list->GetVariableAtIndex(i).get(); if (!variable) continue; const char *variable_name = variable->GetName().AsCString(); if (strstr(variable_name, token.c_str()) == variable_name) { if (strcmp (variable_name, token.c_str()) == 0) { Type *variable_type = variable->GetType(); if (variable_type) { CompilerType variable_compiler_type (variable_type->GetForwardCompilerType ()); PrivateAutoComplete (frame, remaining_partial_path, prefix_path + token, // Anything that has been resolved already will be in here variable_compiler_type.GetCanonicalType(), matches, word_complete); } else { matches.AppendString (prefix_path + variable_name); } } else if (remaining_partial_path.empty()) { matches.AppendString (prefix_path + variable_name); } } } } } break; } } }
static void PrivateAutoCompleteMembers (StackFrame *frame, const std::string &partial_member_name, const std::string &partial_path, const std::string &prefix_path, // Anything that has been resolved already will be in here const CompilerType& compiler_type, StringList &matches, bool &word_complete) { // We are in a type parsing child members const uint32_t num_bases = compiler_type.GetNumDirectBaseClasses(); if (num_bases > 0) { for (uint32_t i = 0; i < num_bases; ++i) { CompilerType base_class_type = compiler_type.GetDirectBaseClassAtIndex(i, nullptr); PrivateAutoCompleteMembers (frame, partial_member_name, partial_path, prefix_path, base_class_type.GetCanonicalType(), matches, word_complete); } } const uint32_t num_vbases = compiler_type.GetNumVirtualBaseClasses(); if (num_vbases > 0) { for (uint32_t i = 0; i < num_vbases; ++i) { CompilerType vbase_class_type = compiler_type.GetVirtualBaseClassAtIndex(i,nullptr); PrivateAutoCompleteMembers (frame, partial_member_name, partial_path, prefix_path, vbase_class_type.GetCanonicalType(), matches, word_complete); } } // We are in a type parsing child members const uint32_t num_fields = compiler_type.GetNumFields(); if (num_fields > 0) { for (uint32_t i = 0; i < num_fields; ++i) { std::string member_name; CompilerType member_compiler_type = compiler_type.GetFieldAtIndex (i, member_name, nullptr, nullptr, nullptr); if (partial_member_name.empty() || member_name.find(partial_member_name) == 0) { if (member_name == partial_member_name) { PrivateAutoComplete (frame, partial_path, prefix_path + member_name, // Anything that has been resolved already will be in here member_compiler_type.GetCanonicalType(), matches, word_complete); } else { matches.AppendString (prefix_path + member_name); } } } } }