diff --git a/lldb/include/lldb/Expression/ClangASTSource.h b/lldb/include/lldb/Expression/ClangASTSource.h index be52f0777372..020a815d0da5 100644 --- a/lldb/include/lldb/Expression/ClangASTSource.h +++ b/lldb/include/lldb/Expression/ClangASTSource.h @@ -17,6 +17,8 @@ #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Target/Target.h" +#include "llvm/ADT/SmallSet.h" + namespace lldb_private { //---------------------------------------------------------------------- @@ -427,11 +429,12 @@ protected: /// Decls given appropriate type information. //---------------------------------------------------------------------- struct NameSearchContext { - ClangASTSource &m_ast_source; ///< The AST source making the request - llvm::SmallVectorImpl &m_decls; ///< The list of declarations already constructed - ClangASTImporter::NamespaceMapSP m_namespace_map; ///< The mapping of all namespaces found for this request back to their modules - const clang::DeclarationName &m_decl_name; ///< The name being looked for - const clang::DeclContext *m_decl_context; ///< The DeclContext to put declarations into + ClangASTSource &m_ast_source; ///< The AST source making the request + llvm::SmallVectorImpl &m_decls; ///< The list of declarations already constructed + ClangASTImporter::NamespaceMapSP m_namespace_map; ///< The mapping of all namespaces found for this request back to their modules + const clang::DeclarationName &m_decl_name; ///< The name being looked for + const clang::DeclContext *m_decl_context; ///< The DeclContext to put declarations into + llvm::SmallSet m_function_types; ///< All the types of functions that have been reported, so we don't report conflicts struct { bool variable : 1; diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp index 8c5971747c79..b1434339bfb0 100644 --- a/lldb/source/Expression/ClangASTSource.cpp +++ b/lldb/source/Expression/ClangASTSource.cpp @@ -1724,6 +1724,11 @@ NameSearchContext::AddFunDecl (void *type) { assert (type && "Type for variable must be non-NULL!"); + if (m_function_types.count(type)) + return NULL; + + m_function_types.insert(type); + clang::FunctionDecl *func_decl = FunctionDecl::Create (*m_ast_source.m_ast_context, const_cast(m_decl_context), SourceLocation(), diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index 6d951c5cef8d..1b67efe2b3a2 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -1328,10 +1328,7 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, if (dyn_cast(decl_ctx)) continue; - // TODO only do this if it's a C function; C++ functions may be - // overloaded - if (!context.m_found.function_with_type_info) - AddOneFunction(context, sym_ctx.function, NULL, current_id); + AddOneFunction(context, sym_ctx.function, NULL, current_id); context.m_found.function_with_type_info = true; context.m_found.function = true; } @@ -1859,6 +1856,18 @@ ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context, if (copied_type) { fun_decl = context.AddFunDecl(copied_type); + + if (!fun_decl) + { + if (log) + { + log->Printf (" Failed to create a function decl for '%s' {0x%8.8" PRIx64 "}", + fun_type->GetName().GetCString(), + fun_type->GetID()); + } + + return; + } } else { diff --git a/lldb/test/lang/cpp/overloaded-functions/Makefile b/lldb/test/lang/cpp/overloaded-functions/Makefile new file mode 100644 index 000000000000..a8d5c4eb0268 --- /dev/null +++ b/lldb/test/lang/cpp/overloaded-functions/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp static-a.cpp static-b.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/lang/cpp/overloaded-functions/TestOverloadedFunctions.py b/lldb/test/lang/cpp/overloaded-functions/TestOverloadedFunctions.py new file mode 100644 index 000000000000..634c28c02ed4 --- /dev/null +++ b/lldb/test/lang/cpp/overloaded-functions/TestOverloadedFunctions.py @@ -0,0 +1,53 @@ +""" +Tests that functions with the same name are resolved correctly. +""" + +import lldb +from lldbtest import * +import lldbutil + +class CPPStaticMethodsTestCase(TestBase): + + mydir = os.path.join("lang", "cpp", "overloaded-functions") + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym_and_run_command(self): + """Test that functions with the same name are resolved correctly""" + self.buildDsym() + self.static_method_commands() + + @dwarf_test + def test_with_dwarf_and_run_command(self): + """Test that functions with the same name are resolved correctly""" + self.buildDwarf() + self.static_method_commands() + + def setUp(self): + TestBase.setUp(self) + self.line = line_number('main.cpp', '// breakpoint') + + def static_method_commands(self): + """Test that static methods are properly distinguished from regular methods""" + self.runCmd("file a.out", 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("process launch", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', 'stop reason = breakpoint']) + + self.expect("expression -- Dump(myB)", + startstr = "(int) $0 = 2") + + self.expect("expression -- Static()", + startstr = "(int) $1 = 1") + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/lang/cpp/overloaded-functions/main.cpp b/lldb/test/lang/cpp/overloaded-functions/main.cpp new file mode 100644 index 000000000000..250e2cd1d96c --- /dev/null +++ b/lldb/test/lang/cpp/overloaded-functions/main.cpp @@ -0,0 +1,43 @@ +#include + +struct A { + int aa; + char ab; +}; + +struct B { + int ba; + int bb; +}; + +struct C { + int ca; + int cb; +}; + +int Dump (A &a) +{ + return 1; +} + +int Dump (B &b) +{ + return 2; +} + +int Dump (C &c) +{ + return 3; +} + +extern int CallStaticA(); +extern int CallStaticB(); + +int main() +{ + A myA; + B myB; + C myC; + + printf("%d\n", CallStaticA() + CallStaticB()); // breakpoint +} diff --git a/lldb/test/lang/cpp/overloaded-functions/static-a.cpp b/lldb/test/lang/cpp/overloaded-functions/static-a.cpp new file mode 100644 index 000000000000..7250fa4bed5e --- /dev/null +++ b/lldb/test/lang/cpp/overloaded-functions/static-a.cpp @@ -0,0 +1,9 @@ +static int Static() +{ + return 1; +} + +int CallStaticA() +{ + return Static(); +} diff --git a/lldb/test/lang/cpp/overloaded-functions/static-b.cpp b/lldb/test/lang/cpp/overloaded-functions/static-b.cpp new file mode 100644 index 000000000000..90a20f69e6db --- /dev/null +++ b/lldb/test/lang/cpp/overloaded-functions/static-b.cpp @@ -0,0 +1,9 @@ +static int Static() +{ + return 1; +} + +int CallStaticB() +{ + return Static(); +}