sivachandra updated this revision to Diff 49138. sivachandra added a comment.
Add more gtest unittests. http://reviews.llvm.org/D17618 Files: include/lldb/Symbol/SymbolFile.h packages/Python/lldbsuite/test/lang/cpp/stl/TestSTL.py packages/Python/lldbsuite/test/lang/cpp/stl/main.cpp source/Expression/IRExecutionUnit.cpp source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h source/Symbol/SymbolFile.cpp unittests/CMakeLists.txt unittests/Language/CMakeLists.txt unittests/Language/CPlusPlus/CMakeLists.txt unittests/Language/CPlusPlus/SplitIntoArgsTest.cpp unittests/Language/CPlusPlus/TypeNamesEqualityTest.cpp
Index: unittests/Language/CPlusPlus/TypeNamesEqualityTest.cpp =================================================================== --- /dev/null +++ unittests/Language/CPlusPlus/TypeNamesEqualityTest.cpp @@ -0,0 +1,32 @@ +//===-- ScalarTest.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" + +using namespace lldb_private; + +TEST(TypeNamesEqualTest, Equality) +{ + ASSERT_TRUE(CPlusPlusLanguage::TypeNamesEqual("int *", "int*")); + ASSERT_TRUE(CPlusPlusLanguage::TypeNamesEqual("unsigned int *", "unsigned int*")); + ASSERT_TRUE(CPlusPlusLanguage::TypeNamesEqual("const unsigned int", "unsigned int const")); + ASSERT_TRUE(CPlusPlusLanguage::TypeNamesEqual("const unsigned int *", "unsigned int const *")); + ASSERT_TRUE(CPlusPlusLanguage::TypeNamesEqual("unsigned int * const", "unsigned int * const")); +} + +TEST(TypeNamesEqualTest, InEquality) +{ + ASSERT_FALSE(CPlusPlusLanguage::TypeNamesEqual("int *", "short int*")); + ASSERT_FALSE(CPlusPlusLanguage::TypeNamesEqual("unsigned int *", "unsigned int")); + ASSERT_FALSE(CPlusPlusLanguage::TypeNamesEqual("const unsigned int", "int const")); + ASSERT_FALSE(CPlusPlusLanguage::TypeNamesEqual("const unsigned int *", "unsigned int * const")); + ASSERT_FALSE(CPlusPlusLanguage::TypeNamesEqual("unsigned int const *", "unsigned int * const")); +} Index: unittests/Language/CPlusPlus/SplitIntoArgsTest.cpp =================================================================== --- /dev/null +++ unittests/Language/CPlusPlus/SplitIntoArgsTest.cpp @@ -0,0 +1,25 @@ +//===-- ScalarTest.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" + +using namespace lldb_private; + +TEST(SplitIntoArgumentsTest, Equality) +{ + llvm::StringRef input = "(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)"; + std::vector<std::string> args; + + CPlusPlusLanguage::SplitIntoArguments(input, args); + ASSERT_EQ(args.size(), static_cast<size_t>(2)); + ASSERT_STREQ(args[0].c_str(), "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"); + ASSERT_STREQ(args[1].c_str(), "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"); +} Index: unittests/Language/CPlusPlus/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/Language/CPlusPlus/CMakeLists.txt @@ -0,0 +1,6 @@ +add_lldb_unittest(LLDBCPlusCPlusLanguageTests + TypeNamesEqualityTest.cpp + SplitIntoArgsTest.cpp + ) + + target_link_libraries(lldbPluginCPlusPlusLanguage) Index: unittests/Language/CMakeLists.txt =================================================================== --- /dev/null +++ unittests/Language/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(CPlusPlus) Index: unittests/CMakeLists.txt =================================================================== --- unittests/CMakeLists.txt +++ unittests/CMakeLists.txt @@ -28,5 +28,6 @@ add_subdirectory(Expression) add_subdirectory(Host) add_subdirectory(Interpreter) +add_subdirectory(Language) add_subdirectory(ScriptInterpreter) add_subdirectory(Utility) Index: source/Symbol/SymbolFile.cpp =================================================================== --- source/Symbol/SymbolFile.cpp +++ source/Symbol/SymbolFile.cpp @@ -135,7 +135,10 @@ } void -SymbolFile::GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names) +SymbolFile::GetMangledNamesForFunction(const SymbolContext &sc, + const std::string &scope_qualified_name, + const std::vector<std::string> &arguments, + std::vector<ConstString> &mangled_names) { return; } Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -209,7 +209,9 @@ lldb_private::SymbolContextList& sc_list) override; void - GetMangledNamesForFunction (const std::string &scope_qualified_name, + GetMangledNamesForFunction (const lldb_private::SymbolContext& sc, + const std::string &scope_qualified_name, + const std::vector<std::string> &arguments, std::vector<lldb_private::ConstString> &mangled_names) override; uint32_t Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2966,7 +2966,9 @@ } void -SymbolFileDWARF::GetMangledNamesForFunction (const std::string &scope_qualified_name, +SymbolFileDWARF::GetMangledNamesForFunction (const SymbolContext& sc, + const std::string &scope_qualified_name, + const std::vector<std::string> &arguments, std::vector<ConstString> &mangled_names) { DWARFDebugInfo* info = DebugInfo(); @@ -2982,18 +2984,42 @@ SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(); if (dwo) - dwo->GetMangledNamesForFunction(scope_qualified_name, mangled_names); + dwo->GetMangledNamesForFunction(sc, scope_qualified_name, arguments, mangled_names); } NameToOffsetMap::iterator iter = m_function_scope_qualified_name_map.find(scope_qualified_name); if (iter == m_function_scope_qualified_name_map.end()) return; + size_t arg_count = arguments.size(); DIERefSetSP set_sp = (*iter).second; std::set<DIERef>::iterator set_iter; for (set_iter = set_sp->begin(); set_iter != set_sp->end(); set_iter++) { DWARFDIE die = DebugInfo()->GetDIE (*set_iter); + + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + TypeSystem *type_system = GetTypeSystemForLanguage(die.GetCU()->GetLanguageType()); + DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); + TypeSP type_sp = dwarf_ast->ParseTypeFromDWARF (sc, die, log, NULL); + CompilerType compiler_type = type_sp->GetFullCompilerType(); + + if (compiler_type.GetNumberOfFunctionArguments() != arg_count) + continue; + + size_t match_count = 0; + for (size_t i = 0; i < compiler_type.GetNumberOfFunctionArguments(); i++) + { + std::string arg_type = compiler_type.GetFunctionArgumentAtIndex(i).GetTypeName().AsCString(); + if (CPlusPlusLanguage::TypeNamesEqual(llvm::StringRef(arguments[i]), llvm::StringRef(arg_type))) + match_count++; + else + break; + } + + if (match_count != arg_count) + continue; + mangled_names.push_back(ConstString(die.GetMangledName())); } } Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h =================================================================== --- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -99,7 +99,7 @@ llvm::StringRef GetContext (); - llvm::StringRef + const std::vector<std::string> & GetArguments (); llvm::StringRef @@ -109,10 +109,13 @@ void Parse(); + void + SetArguments(const llvm::StringRef &arg_string); + ConstString m_full; // Full name: "lldb::SBTarget::GetBreakpointAtIndex(unsigned int) const" llvm::StringRef m_basename; // Basename: "GetBreakpointAtIndex" llvm::StringRef m_context; // Decl context: "lldb::SBTarget" - llvm::StringRef m_arguments; // Arguments: "(unsigned int)" + std::vector<std::string> m_arguments; // Arguments: ["unsigned int"] llvm::StringRef m_qualifiers; // Qualifiers: "const" Type m_type; bool m_parsed; @@ -137,7 +140,7 @@ HardcodedFormatters::HardcodedSyntheticFinder GetHardcodedSynthetics () override; - + //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ @@ -165,7 +168,13 @@ static bool ExtractContextAndIdentifier (const char *name, llvm::StringRef &context, llvm::StringRef &identifier); + + static bool + TypeNamesEqual(const llvm::StringRef &t1, const llvm::StringRef &t2); + static void + SplitIntoArguments(const llvm::StringRef &arg_str, std::vector<std::string> &args); + // in some cases, compilers will output different names for one same type. when that happens, it might be impossible // to construct SBType objects for a valid type, because the name that is available is not the same as the name that // can be used as a search key in FindTypes(). the equivalents map here is meant to return possible alternative names Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp =================================================================== --- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -89,7 +89,7 @@ m_full.Clear(); m_basename = llvm::StringRef(); m_context = llvm::StringRef(); - m_arguments = llvm::StringRef(); + m_arguments = std::vector<std::string>(); m_qualifiers = llvm::StringRef(); m_type = eTypeInvalid; m_parsed = false; @@ -195,7 +195,7 @@ llvm::StringRef parens("()", 2); if (ReverseFindMatchingChars (full, parens, arg_start, arg_end)) { - m_arguments = full.substr(arg_start, arg_end - arg_start + 1); + SetArguments(full.substr(arg_start, arg_end - arg_start + 1)); if (arg_end + 1 < full.size()) m_qualifiers = full.substr(arg_end + 1); if (arg_start > 0) @@ -253,7 +253,7 @@ // be a valid C++ method, clear everything out and indicate an error m_context = llvm::StringRef(); m_basename = llvm::StringRef(); - m_arguments = llvm::StringRef(); + m_arguments = std::vector<std::string>(); m_qualifiers = llvm::StringRef(); m_parse_error = true; } @@ -281,14 +281,20 @@ return m_context; } -llvm::StringRef +const std::vector<std::string> & CPlusPlusLanguage::MethodName::GetArguments () { if (!m_parsed) Parse(); return m_arguments; } +void +CPlusPlusLanguage::MethodName::SetArguments(const llvm::StringRef &arg_str) +{ + SplitIntoArguments(arg_str, m_arguments); +} + llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers () { @@ -313,6 +319,103 @@ return res; } +void +CPlusPlusLanguage::SplitIntoArguments (const llvm::StringRef &arg_str, std::vector<std::string> &args) +{ + // Remove the open and close parenthesis. + llvm::StringRef input = arg_str.substr(1, arg_str.size() - 2); + int paren_count = 0; + int angle_count = 0; + + std::string arg; + for (size_t i = 0; i < input.size(); i++) + { + char c = input[i]; + switch (c) + { + case ',': + if (paren_count == 0 && angle_count == 0) + { + args.push_back(arg.substr()); + arg.erase(); + continue; + } + break; + case '(': + paren_count++; + break; + case '<': + angle_count++; + break; + case ')': + paren_count--; + break; + case '>': + angle_count--; + break; + case ' ': + if (arg.size() == 0) + continue; + default: + break; + } + + arg.push_back(c); + } + + if (arg.size() > 0) + args.push_back(arg); +} + +bool +CPlusPlusLanguage::TypeNamesEqual (const llvm::StringRef &t1, const llvm::StringRef &t2) +{ + llvm::StringRef r1 = t1.trim(); + llvm::StringRef r2 = t2.trim(); + + if (r1 == r2) + return true; + + char last = r1.back(); + if (last == '&' || last == '*') + { + if (r2.back() != last) + return false; + + return CPlusPlusLanguage::TypeNamesEqual(r1.drop_back(), r2.drop_back()); + } + + if (r1.endswith("const")) + { + // If both end with "const", drop strlen("const") from the back and compare. + if (r2.endswith("const")) + return CPlusPlusLanguage::TypeNamesEqual(r1.drop_back(5), r2.drop_back(5)); + + // If r2 starts with "const", then drop strlen("const") from its front and + // compare with r1 after dropping strlen("const") from its back. + if (r2.startswith("const")) + return CPlusPlusLanguage::TypeNamesEqual(r1.drop_back(5), r2.drop_front(5)); + + return false; + } + + if (r1.startswith("const")) + { + // If both start with "const", drop strlen("const") from the front and compare. + if (r2.startswith("const")) + return CPlusPlusLanguage::TypeNamesEqual(r1.drop_front(5), r2.drop_front(5)); + + // If r2 ends with "const", then drop strlen("const") from its back and + // compare with r1 after dropping strlen("const") from its front. + if (r2.endswith("const")) + return CPlusPlusLanguage::TypeNamesEqual(r1.drop_front(5), r2.drop_back(5)); + + return false; + } + + return false; +} + bool CPlusPlusLanguage::IsCPPMangledName (const char *name) { Index: source/Expression/IRExecutionUnit.cpp =================================================================== --- source/Expression/IRExecutionUnit.cpp +++ source/Expression/IRExecutionUnit.cpp @@ -653,6 +653,7 @@ { CPlusPlusLanguage::MethodName cpp_name(demangled); std::string scope_qualified_name = cpp_name.GetScopeQualifiedName(); + const std::vector<std::string> &arguments = cpp_name.GetArguments(); if (!scope_qualified_name.size()) return ConstString(); @@ -669,7 +670,7 @@ return ConstString(); std::vector<ConstString> alternates; - sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates); + sym_file->GetMangledNamesForFunction(sym_ctx, scope_qualified_name, arguments, alternates); std::vector<ConstString> param_and_qual_matches; std::vector<ConstString> param_matches; @@ -683,13 +684,10 @@ if (!cpp_name.IsValid()) continue; - if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) - { - if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers()) - param_and_qual_matches.push_back(alternate_mangled_name); - else - param_matches.push_back(alternate_mangled_name); - } + if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers()) + param_and_qual_matches.push_back(alternate_mangled_name); + else + param_matches.push_back(alternate_mangled_name); } if (param_and_qual_matches.size()) Index: packages/Python/lldbsuite/test/lang/cpp/stl/main.cpp =================================================================== --- packages/Python/lldbsuite/test/lang/cpp/stl/main.cpp +++ packages/Python/lldbsuite/test/lang/cpp/stl/main.cpp @@ -13,11 +13,14 @@ int main (int argc, char const *argv[]) { std::string hello_world ("Hello World!"); + std::string str("a_string"); std::cout << hello_world << std::endl; std::cout << hello_world.length() << std::endl; std::cout << hello_world[11] << std::endl; std::map<std::string, int> associative_array; + std::map<std::string, std::string> ssmap; + ssmap[str] = hello_world; std::cout << "size of upon construction associative_array: " << associative_array.size() << std::endl; associative_array[hello_world] = 1; associative_array["hello"] = 2; Index: packages/Python/lldbsuite/test/lang/cpp/stl/TestSTL.py =================================================================== --- packages/Python/lldbsuite/test/lang/cpp/stl/TestSTL.py +++ packages/Python/lldbsuite/test/lang/cpp/stl/TestSTL.py @@ -24,6 +24,23 @@ self.source = 'main.cpp' self.line = line_number(self.source, '// Set break point at this line.') + def test_string_maps(self): + self.build() + exe = os.path.join(os.getcwd(), "a.out") + + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) + self.runCmd("run", RUN_SUCCEEDED) + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['main.cpp:%d' % self.line, + 'stop reason = breakpoint']) + + self.expect('expr associative_array[hello_world]', + substrs = [' = 1']) + self.expect('expr ssmap[str]', + substrs = [' = "Hello World!"']) + # rdar://problem/10400981 @unittest2.expectedFailure def test(self): Index: include/lldb/Symbol/SymbolFile.h =================================================================== --- include/lldb/Symbol/SymbolFile.h +++ include/lldb/Symbol/SymbolFile.h @@ -146,7 +146,7 @@ virtual uint32_t FindTypes (const SymbolContext& sc, const ConstString &name, const CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap& types); virtual size_t FindTypes (const std::vector<CompilerContext> &context, bool append, TypeMap& types); - virtual void GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names); + virtual void GetMangledNamesForFunction(const SymbolContext& sc, const std::string &scope_qualified_name, const std::vector<std::string> &arguments, std::vector<ConstString> &mangled_names); // virtual uint32_t FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, TypeList& types) = 0; virtual TypeList * GetTypeList (); virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits