dawn updated this revision to Diff 42115.
dawn added a comment.

Updated patch to removed change related to Pascal language - it should be part 
of a separate patch.


Repository:
  rL LLVM

http://reviews.llvm.org/D15312

Files:
  include/lldb/Symbol/ClangASTContext.h
  include/lldb/Symbol/GoASTContext.h
  include/lldb/Symbol/TypeSystem.h
  packages/Python/lldbsuite/test/lang/cpp/namespace/Makefile
  packages/Python/lldbsuite/test/lang/cpp/namespace/TestNamespaceLookup.py
  packages/Python/lldbsuite/test/lang/cpp/namespace/main.cpp
  packages/Python/lldbsuite/test/lang/cpp/namespace/ns.cpp
  packages/Python/lldbsuite/test/lang/cpp/namespace/ns.h
  packages/Python/lldbsuite/test/lang/cpp/namespace/ns2.cpp
  packages/Python/lldbsuite/test/lang/cpp/namespace/ns3.cpp
  source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
  source/Symbol/ClangASTContext.cpp

Index: source/Symbol/ClangASTContext.cpp
===================================================================
--- source/Symbol/ClangASTContext.cpp
+++ source/Symbol/ClangASTContext.cpp
@@ -9224,6 +9224,98 @@
     return found_decls;
 }
 
+// Look for opaque_find_decl_ctx's lookup scope in opaque_decl_ctx and its parents,
+// and return the number of levels it took to find it, or LLDB_INVALID_DECL_LEVEL
+// if not found.  If the decl was imported via a using declaration, its name and
+// type, if set, will be used to check that the decl found in the scope is a match.
+//
+// NOTE: Because file statics are at the TranslationUnit along with globals, a
+// function at file scope will return the same level as a function at global scope.
+// Ideally we'd like to treat the file scope as an additional scope just below the
+// global scope.  More work needs to be done to recognise that, if the decl we're
+// trying to look up is static, we should compare its source file with that of the
+// current scope and return a lower number for it.
+uint32_t
+ClangASTContext::DeclContextCountDeclLevels(void *opaque_decl_ctx,
+                                            void *opaque_find_decl_ctx,
+                                            ConstString *find_name,
+                                            CompilerType *find_type)
+{
+    int level = LLDB_INVALID_DECL_LEVEL;
+    if (opaque_decl_ctx)
+    {
+        DeclContext *root_decl_ctx = (DeclContext *)opaque_decl_ctx;
+        DeclContext *find_decl_ctx = (DeclContext *)opaque_find_decl_ctx;
+        std::set<DeclContext *> searched;
+        std::multimap<DeclContext *, DeclContext *> search_queue;
+        SymbolFile *symbol_file = GetSymbolFile();
+
+        // Get the lookup scope for the decl we're trying to find.
+        find_decl_ctx = find_decl_ctx->getLookupParent();
+
+        // Look for it in our scope's decl context and its parents.
+        for (clang::DeclContext *decl_context = root_decl_ctx; decl_context != nullptr; decl_context = decl_context->getParent())
+        {
+            if (!decl_context->isLookupContext())
+                continue;
+            ++level;
+            if (decl_context == find_decl_ctx)
+                // Found it!
+                return level;
+            search_queue.insert(std::make_pair(decl_context, decl_context));
+
+            for (auto it = search_queue.find(decl_context); it != search_queue.end(); it++)
+            {
+                if (searched.find(it->second) != searched.end())
+                    continue;
+                searched.insert(it->second);
+                symbol_file->ParseDeclsForContext(CompilerDeclContext(this, it->second));
+
+                for (clang::Decl *child : it->second->decls())
+                {
+                    if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast<clang::UsingDirectiveDecl>(child))
+                    {
+                        clang::DeclContext *ns = ud->getNominatedNamespace();
+                        if (ns == find_decl_ctx)
+                            // Found it!
+                            return level;
+                        clang::DeclContext *from = ud->getCommonAncestor();
+                        if (searched.find(ns) == searched.end())
+                            search_queue.insert(std::make_pair(from, ns));
+                    }
+                    else if (find_name)
+                    {
+                        if (clang::UsingDecl *ud = llvm::dyn_cast<clang::UsingDecl>(child))
+                        {
+                            for (clang::UsingShadowDecl *usd : ud->shadows())
+                            {
+                                clang::Decl *target = usd->getTargetDecl();
+                                clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target);
+                                if (!nd)
+                                    continue;
+                                // Check names.
+                                IdentifierInfo *ii = nd->getIdentifier();
+                                if (ii == nullptr || !ii->getName().equals(find_name->AsCString(nullptr)))
+                                    continue;
+                                // Check types, if one was provided.
+                                if (find_type)
+                                {
+                                    CompilerType clang_type = ClangASTContext::GetTypeForDecl(nd);
+                                    if (!AreTypesSame(clang_type, *find_type, /*ignore_qualifiers=*/true))
+                                        continue;
+                                }
+                                // Found it!
+                                return level;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return level;
+}
+
 bool
 ClangASTContext::DeclContextIsStructUnionOrClass (void *opaque_decl_ctx)
 {
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1424,6 +1424,164 @@
                                                   sc_list);
             }
 
+            // If we found more than one function, see if we can use the
+            // frame's decl context to remove functions that are shadowed
+            // by other functions which match in type but are nearer in scope.
+            //
+            // AddOneFunction will not add a function whose type has already been
+            // added, so if there's another function in the list with a matching
+            // type, check to see if their decl context is a parent of the current
+            // frame's or was imported via a and using statement, and pick the
+            // best match according to lookup rules.
+            if (sc_list.GetSize() > 1)
+            {
+                // Collect some info about our frame's context.
+                StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+                SymbolContext comp_sym_ctx;
+                if (frame != nullptr)
+                    comp_sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction|lldb::eSymbolContextBlock);
+                CompilerDeclContext compiler_decl_context = comp_sym_ctx.block != nullptr ? comp_sym_ctx.block->GetDeclContext() : CompilerDeclContext();
+
+                // We can't do this without a compiler decl context for our frame.
+                if (compiler_decl_context)
+                {
+                    // First symplify things by looping through the symbol contexts
+                    // to remove unwanted functions and separate out the symbols
+                    // into a separate list.
+                    SymbolContextList sc_func_list;
+                    SymbolContextList sc_sym_list;
+                    for (uint32_t index = 0, num_indices = sc_list.GetSize();
+                        index < num_indices;
+                        ++index)
+                    {
+                        SymbolContext sym_ctx;
+                        sc_list.GetContextAtIndex(index, sym_ctx);
+
+                        if (sym_ctx.function)
+                        {
+                            CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext();
+                            if (!decl_ctx)
+                                continue;
+
+                            // Filter out class/instance methods.
+                            if (decl_ctx.IsClassMethod(nullptr, nullptr, nullptr))
+                                continue;
+                            sc_func_list.Append(sym_ctx);
+                        }
+                        else
+                            sc_sym_list.Append(sym_ctx);
+                    }
+
+                    ClangASTContext *ast = llvm::dyn_cast_or_null<ClangASTContext>(compiler_decl_context.GetTypeSystem());
+
+                    // Structure to hold the info needed when comparing function
+                    // declarations.
+                    struct FuncDeclInfo
+                    {
+                        ConstString m_function_name;
+                        CompilerType m_copied_function_type;
+                        uint32_t m_func_decl_lvl;
+                    };
+                    auto initFuncDeclInfo = [this, compiler_decl_context, ast](const SymbolContext &sym_ctx)
+                    {
+                        FuncDeclInfo fdi;
+                        Function *function = sym_ctx.function;
+                        fdi.m_function_name = function->GetName();
+
+                        CompilerType funct_clang_type;
+                        funct_clang_type = function->GetType()->GetFullCompilerType();
+                        fdi.m_copied_function_type = this->GuardedCopyType(funct_clang_type);
+                        CompilerDeclContext func_decl_context;
+                        func_decl_context = function->GetDeclContext();
+                        fdi.m_func_decl_lvl = LLDB_INVALID_DECL_LEVEL;
+                        if (fdi.m_copied_function_type && func_decl_context)
+                        {
+                            // Call DeclContextFindDeclLevel to get the number of
+                            // parent scopes we have to look through before we
+                            // find the function declaration.
+                            // When comparing functions of the same type, the one
+                            // with a lower count will be closer to us in the lookup
+                            // scope and shadows the other.
+                            fdi.m_func_decl_lvl =
+                                ast->DeclContextCountDeclLevels(compiler_decl_context.GetOpaqueDeclContext(),
+                                                                func_decl_context.GetOpaqueDeclContext(),
+                                                                &fdi.m_function_name,
+                                                                &fdi.m_copied_function_type);
+                        }
+                        return fdi;
+                    };
+
+                    // Cache the info needed about the function declarations in a
+                    // vector for efficiency.
+                    uint32_t num_indices = sc_func_list.GetSize();
+                    std::vector<FuncDeclInfo> fdi_cache;
+                    fdi_cache.reserve(num_indices);
+                    for (uint32_t index = 0; index < num_indices; ++index)
+                    {
+                        SymbolContext sym_ctx;
+                        sc_func_list.GetContextAtIndex(index, sym_ctx);
+
+                        struct FuncDeclInfo fdi = initFuncDeclInfo(sym_ctx);
+                        fdi_cache.emplace_back(fdi);
+                    }
+
+                    // Loop through the functions looking for matching types,
+                    // then compare their scope levels to see which is closer.
+                    SymbolContextList sc_func_list2;
+                    for (uint32_t index = 0; index < num_indices; ++index)
+                    {
+                        SymbolContext sym_ctx1;
+                        sc_func_list.GetContextAtIndex(index, sym_ctx1);
+                        struct FuncDeclInfo fdi1 = fdi_cache[index];
+
+                        // Is there another function in the list with the same type?
+                        uint32_t index2 = index + 1;
+                        do {
+                            SymbolContext sym_ctx2;
+                            sc_func_list.GetContextAtIndex(index2, sym_ctx2);
+                            struct FuncDeclInfo fdi2 = fdi_cache[index2];
+
+                            if (fdi1.m_copied_function_type && fdi2.m_copied_function_type &&
+                                fdi1.m_copied_function_type == fdi2.m_copied_function_type)
+                            {
+                                // We have a match.  If one function is closer to us
+                                // in the lookup scope, remove the other from the list.
+                                if (fdi1.m_func_decl_lvl == fdi2.m_func_decl_lvl)
+                                {
+                                    // FIXME: ambiguous!  Should report error, but this
+                                    // can happen for static functions.  See comment in
+                                    // DeclContextCountDeclLevels.  For now, keep fdi1.
+                                }
+                                else if (fdi1.m_func_decl_lvl < fdi2.m_func_decl_lvl)
+                                {
+                                    // fdi1 shadows fdi2; keep fdi1.
+                                }
+                                else
+                                {
+                                    // fdi2 shadows fdi1; replace fdi1 with fdi2.
+                                    sym_ctx1 = sym_ctx2;
+                                    fdi1 = fdi2;
+                                }
+                                // Remove fdi2 from the list so we don't revisit it.
+                                sc_func_list.RemoveContextAtIndex(index2);
+                                fdi_cache.erase(fdi_cache.begin() + index2);
+                                --num_indices;
+                            }
+                            else
+                            {
+                                ++index2;
+                            }
+                        }
+                        while (index2 < num_indices);
+                        // Add this function.
+                        sc_func_list2.Append(sym_ctx1);
+                    }
+                    // Rejoin the lists.
+                    sc_list = sc_func_list2;
+                    sc_list.Append(sc_sym_list);
+                }
+            }
+
             if (sc_list.GetSize())
             {
                 Symbol *extern_symbol = NULL;
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/ns3.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/ns3.cpp
@@ -0,0 +1,33 @@
+//===-- ns3.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ns.h"
+extern int func();
+
+// Note: the following function must be before the using.
+void test_lookup_before_using_directive()
+{
+    // BP_before_using_directive
+
+    printf("func() = %d\n", func()); // eval func(), exp: 1
+}
+using namespace A;
+void test_lookup_after_using_directive()
+{
+    // BP_after_using_directive
+
+    //printf("func() = %d\n", func()); // eval func(), exp: error, amiguous
+
+    printf("func2() = %d\n", func2()); // eval func2(), exp: 3
+
+    printf("::func() = %d\n", ::func()); // eval ::func(), exp: 1
+
+    printf("B::func() = %d\n", B::func()); // eval B::func(), exp: 4
+}
+
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/ns2.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/ns2.cpp
@@ -0,0 +1,74 @@
+//===-- ns2.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ns.h"
+
+static int func()
+{
+    printf("static m2.cpp func()\n");
+    return 2;
+}
+void test_lookup_at_file_scope()
+{
+    // BP_file_scope
+
+    printf("func() = %d\n", func()); // eval func(), exp: 2
+
+    printf("func(10) = %d\n", func(10)); // eval func(10), exp: 11
+}
+namespace A {
+    namespace B {
+	int func()
+	{
+	    printf("A::B::func()\n");
+	    return 4;
+	}
+	void test_lookup_at_nested_ns_scope()
+	{
+	    // BP_nested_ns_scope
+
+	    printf("func() = %d\n", func()); // eval func(), exp: 4
+
+	    //printf("func(10) = %d\n", func(10)); // eval func(10), exp: 13
+	    // NOTE: Under the rules of C++, this test would normally get an error 
+	    // because A::B::func() hides A::func(), but lldb intentionally
+	    // disobeys these rules so that the intended overload can be found
+	    // by only removing duplicates if they have the same type.
+	}
+	void test_lookup_at_nested_ns_scope_after_using()
+	{
+	    // BP_nested_ns_scope_after_using
+	    using A::func;
+
+	    printf("func() = %d\n", func()); // eval func(), exp: 3
+
+	    printf("A::func(10) = %d\n", A::func(10)); // eval A::func(10), exp: 13
+	}
+    }
+}
+int A::foo()
+{
+    printf("A::foo()\n");
+    return 42;
+}
+int A::func(int a)
+{
+    printf("A::func(int)\n");
+    return a + 3;
+}
+void A::test_lookup_at_ns_scope()
+{
+    // BP_ns_scope
+
+    printf("func() = %d\n", func()); // eval func(), exp: 3
+
+    printf("func(10) = %d\n", func(10)); // eval func(10), exp: 13
+
+    printf("foo() = %d\n", foo()); // eval foo(), exp: 42
+}
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/ns.h
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/ns.h
@@ -0,0 +1,36 @@
+//===-- ns.h ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+void test_lookup_at_global_scope();
+void test_lookup_at_file_scope();
+void test_lookup_before_using_directive();
+void test_lookup_after_using_directive();
+int func(int a);
+namespace A {
+    int foo();
+    int func(int a);
+    inline int func()
+    {
+	printf("A::func()\n");
+        return 3;
+    }
+    inline int func2()
+    {
+	printf("A::func2()\n");
+        return 3;
+    }
+    void test_lookup_at_ns_scope();
+    namespace B {
+	int func();
+	void test_lookup_at_nested_ns_scope();
+	void test_lookup_at_nested_ns_scope_after_using();
+    }
+}
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/ns.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/ns.cpp
@@ -0,0 +1,32 @@
+//===-- ns.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ns.h"
+
+int foo()
+{
+    printf("global foo()\n");
+    return 42;
+}
+int func()
+{
+    printf("global func()\n");
+    return 1;
+}
+int func(int a)
+{
+    printf("global func(int)\n");
+    return a + 1;
+}
+void test_lookup_at_global_scope()
+{
+    // BP_global_scope
+    printf("foo() = %d\n", foo()); // eval foo(), exp: 42
+    printf("func() = %d\n", func()); // eval func(), exp: 1
+}
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/main.cpp
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/namespace/main.cpp
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/main.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include <cstdarg>
+#include "ns.h"
 
 namespace {
     typedef unsigned int my_uint_t;
@@ -80,7 +81,6 @@
     int value = 200;
 }
 
-#include <stdio.h>
 void test_namespace_scopes() {
     do {
         using namespace ns1;
@@ -113,5 +113,12 @@
 int
 main (int argc, char const *argv[])
 {
+    test_lookup_at_global_scope();
+    test_lookup_at_file_scope();
+    A::test_lookup_at_ns_scope();
+    A::B::test_lookup_at_nested_ns_scope();
+    A::B::test_lookup_at_nested_ns_scope_after_using();
+    test_lookup_before_using_directive();
+    test_lookup_after_using_directive();
     return Foo::myfunc(12);
 }
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/TestNamespaceLookup.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/TestNamespaceLookup.py
@@ -0,0 +1,216 @@
+"""
+Test the printing of anonymous and named namespace variables.
+"""
+
+from __future__ import print_function
+
+
+import os, time
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class NamespaceLookupTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Break inside different scopes and evaluate value
+        self.line_break_global_scope = line_number('ns.cpp', '// BP_global_scope')
+        self.line_break_file_scope = line_number('ns2.cpp', '// BP_file_scope')
+        self.line_break_ns_scope = line_number('ns2.cpp', '// BP_ns_scope')
+        self.line_break_nested_ns_scope = line_number('ns2.cpp', '// BP_nested_ns_scope')
+        self.line_break_nested_ns_scope_after_using = line_number('ns2.cpp', '// BP_nested_ns_scope_after_using')
+        self.line_break_before_using_directive = line_number('ns3.cpp', '// BP_before_using_directive')
+        self.line_break_after_using_directive = line_number('ns3.cpp', '// BP_after_using_directive')
+
+    def runToBkpt(self, command):
+        self.runCmd(command, RUN_SUCCEEDED)
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+    def test_scope_lookup_with_run_command(self):
+        """Test scope lookup of functions in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns.cpp", self.line_break_global_scope, num_expected_locations=1, loc_exact=False)
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_ns_scope, num_expected_locations=1, loc_exact=False)
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_nested_ns_scope, num_expected_locations=1, loc_exact=False)
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_nested_ns_scope_after_using, num_expected_locations=1, loc_exact=False)
+        lldbutil.run_break_set_by_file_and_line (self, "ns3.cpp", self.line_break_before_using_directive, num_expected_locations=1, loc_exact=False)
+        lldbutil.run_break_set_by_file_and_line (self, "ns3.cpp", self.line_break_after_using_directive, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_global_scope at global scope
+        self.runToBkpt("run")
+        # Evaluate func() - should call ::func()
+        self.expect("expr -- func()", startstr = "(int) $0 = 1")
+        # Evaluate A::B::func() - should call A::B::func()
+        self.expect("expr -- A::B::func()", startstr = "(int) $1 = 4")
+        # Evaluate func(10) - should call ::func(int)
+        self.expect("expr -- func(10)", startstr = "(int) $2 = 11")
+        # Evaluate ::func() - should call A::func()
+        self.expect("expr -- ::func()", startstr = "(int) $3 = 1")
+        # Evaluate A::foo() - should call A::foo()
+        self.expect("expr -- A::foo()", startstr = "(int) $4 = 42")
+
+        # Continue to BP_ns_scope at ns scope
+        self.runToBkpt("continue")
+        # Evaluate func(10) - should call A::func(int)
+        self.expect("expr -- func(10)", startstr = "(int) $5 = 13")
+        # Evaluate B::func() - should call B::func()
+        self.expect("expr -- B::func()", startstr = "(int) $6 = 4")
+        # Evaluate func() - should call A::func()
+        self.expect("expr -- func()", startstr = "(int) $7 = 3")
+
+        # Continue to BP_nested_ns_scope at nested ns scope
+        self.runToBkpt("continue")
+        # Evaluate func() - should call A::B::func()
+        self.expect("expr -- func()", startstr = "(int) $8 = 4")
+        # Evaluate A::func() - should call A::func()
+        self.expect("expr -- A::func()", startstr = "(int) $9 = 3")
+
+        # Evaluate func(10) - should call A::func(10)
+        # NOTE: Under the rules of C++, this test would normally get an error
+        # because A::B::func() hides A::func(), but lldb intentionally
+        # disobeys these rules so that the intended overload can be found
+        # by only removing duplicates if they have the same type.
+        self.expect("expr -- func(10)", startstr = "(int) $10 = 13")
+
+        # Continue to BP_nested_ns_scope_after_using at nested ns scope after using declaration
+        self.runToBkpt("continue")
+        # Evaluate A::func(10) - should call A::func(int)
+        self.expect("expr -- A::func(10)", startstr = "(int) $11 = 13")
+
+        # Continue to BP_before_using_directive at global scope before using declaration
+        self.runToBkpt("continue")
+        # Evaluate ::func() - should call ::func()
+        self.expect("expr -- ::func()", startstr = "(int) $12 = 1")
+        # Evaluate B::func() - should call B::func()
+        self.expect("expr -- B::func()", startstr = "(int) $13 = 4")
+
+        # Continue to BP_after_using_directive at global scope after using declaration
+        self.runToBkpt("continue")
+        # Evaluate ::func() - should call ::func()
+        self.expect("expr -- ::func()", startstr = "(int) $14 = 1")
+        # Evaluate B::func() - should call B::func()
+        self.expect("expr -- B::func()", startstr = "(int) $15 = 4")
+
+    @unittest2.expectedFailure("lldb scope lookup of functions bugs")
+    def test_function_scope_lookup_with_run_command(self):
+        """Test scope lookup of functions in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns.cpp", self.line_break_global_scope, num_expected_locations=1, loc_exact=False)
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_ns_scope, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_global_scope at global scope
+        self.runToBkpt("run")
+        # Evaluate foo() - should call ::foo()
+        # FIXME: lldb finds Y::foo because lookup for variables is done
+        # before functions.
+        self.expect("expr -- foo()", startstr = "(int) $0 = 42")
+        # Evaluate ::foo() - should call ::foo()
+        # FIXME: lldb finds Y::foo because lookup for variables is done
+        # before functions and :: is ignored.
+        self.expect("expr -- ::foo()", startstr = "(int) $1 = 42")
+
+        # Continue to BP_ns_scope at ns scope
+        self.runToBkpt("continue")
+        # Evaluate foo() - should call A::foo()
+        # FIXME: lldb finds Y::foo because lookup for variables is done
+        # before functions.
+        self.expect("expr -- foo()", startstr = "(int) $2 = 42")
+
+    @unittest2.expectedFailure("lldb file scope lookup bugs")
+    def test_file_scope_lookup_with_run_command(self):
+        """Test file scope lookup in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_file_scope, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_file_scope at file scope
+        self.runToBkpt("run")
+        # Evaluate func() - should call static ns2.cpp:func()
+        # FIXME: This test fails because lldb doesn't know about file scopes so
+        # finds the global ::func().
+        self.expect("expr -- func()", startstr = "(int) $0 = 2")
+
+    def test_scope_lookup_before_using_with_run_command(self):
+        """Test scope lookup before using in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns3.cpp", self.line_break_before_using_directive, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_before_using_directive at global scope before using declaration
+        self.runToBkpt("run")
+        # Evaluate func() - should call ::func()
+        self.expect("expr -- func()", startstr = "(int) $0 = 1")
+
+    # NOTE: this test may fail on older systems that don't emit import
+    # emtries in DWARF - may need to add checks for compiler versions here.
+    def test_scope_after_using_directive_lookup_with_run_command(self):
+        """Test scope lookup after using directive in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns3.cpp", self.line_break_after_using_directive, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_after_using_directive at global scope after using declaration
+        self.runToBkpt("run")
+        # Evaluate func2() - should call A::func2()
+        self.expect("expr -- func2()", startstr = "(int) $0 = 3")
+
+    @unittest2.expectedFailure("lldb scope lookup after using declaration bugs")
+    # NOTE: this test may fail on older systems that don't emit import
+    # emtries in DWARF - may need to add checks for compiler versions here.
+    def test_scope_after_using_declaration_lookup_with_run_command(self):
+        """Test scope lookup after using declaration in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_nested_ns_scope_after_using, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_nested_ns_scope_after_using at nested ns scope after using declaration
+        self.runToBkpt("run")
+        # Evaluate func() - should call A::func()
+        self.expect("expr -- func()", startstr = "(int) $0 = 3")
+
+    @unittest2.expectedFailure("lldb scope lookup ambiguity after using bugs")
+    def test_scope_ambiguity_after_using_lookup_with_run_command(self):
+        """Test scope lookup ambiguity after using in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns3.cpp", self.line_break_after_using_directive, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_after_using_directive at global scope after using declaration
+        self.runToBkpt("run")
+        # Evaluate func() - should get error: ambiguous
+        # FIXME: This test fails because lldb removes duplicates if they have
+        # the same type.
+        self.expect("expr -- func()", startstr = "error")
+
+    def test_scope_lookup_shadowed_by_using_with_run_command(self):
+        """Test scope lookup shadowed by using in lldb."""
+        self.build()
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "ns2.cpp", self.line_break_nested_ns_scope, num_expected_locations=1, loc_exact=False)
+
+        # Run to BP_nested_ns_scope at nested ns scope
+        self.runToBkpt("run")
+        # Evaluate func(10) - should call A::func(10)
+        # NOTE: Under the rules of C++, this test would normally get an error
+        # because A::B::func() shadows A::func(), but lldb intentionally
+        # disobeys these rules so that the intended overload can be found
+        # by only removing duplicates if they have the same type.
+        self.expect("expr -- func(10)", startstr = "(int) $0 = 13")
+
Index: packages/Python/lldbsuite/test/lang/cpp/namespace/Makefile
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/namespace/Makefile
+++ packages/Python/lldbsuite/test/lang/cpp/namespace/Makefile
@@ -1,5 +1,5 @@
 LEVEL = ../../../make
 
-CXX_SOURCES := main.cpp
+CXX_SOURCES := main.cpp ns.cpp ns2.cpp ns3.cpp
 
 include $(LEVEL)/Makefile.rules
Index: include/lldb/Symbol/TypeSystem.h
===================================================================
--- include/lldb/Symbol/TypeSystem.h
+++ include/lldb/Symbol/TypeSystem.h
@@ -144,6 +144,14 @@
     virtual std::vector<void *>
     DeclContextFindDeclByName (void *opaque_decl_ctx, ConstString name) = 0;
 
+#define LLDB_INVALID_DECL_LEVEL            UINT32_MAX
+    // LLDB_INVALID_DECL_LEVEL is returned by DeclContextCountDeclLevels if
+    // opaque_find_decl_ctx could not be found in opaque_decl_ctx.
+    virtual uint32_t
+    DeclContextCountDeclLevels (void *opaque_decl_ctx,
+                                void *opaque_find_decl_ctx,
+                                ConstString *find_name = nullptr,
+                                CompilerType *find_type = nullptr) = 0;
     virtual bool
     DeclContextIsStructUnionOrClass (void *opaque_decl_ctx) = 0;
 
Index: include/lldb/Symbol/GoASTContext.h
===================================================================
--- include/lldb/Symbol/GoASTContext.h
+++ include/lldb/Symbol/GoASTContext.h
@@ -106,6 +106,15 @@
         return std::vector<void *>();
     }
 
+    uint32_t
+    DeclContextCountDeclLevels (void *opaque_decl_ctx,
+                                void *opaque_find_decl_ctx,
+                                ConstString *find_name = nullptr,
+                                CompilerType *find_type = nullptr) override
+    {
+        return LLDB_INVALID_DECL_LEVEL;
+    }
+
     bool
     DeclContextIsStructUnionOrClass(void *opaque_decl_ctx) override
     {
Index: include/lldb/Symbol/ClangASTContext.h
===================================================================
--- include/lldb/Symbol/ClangASTContext.h
+++ include/lldb/Symbol/ClangASTContext.h
@@ -558,6 +558,12 @@
     std::vector<void *>
     DeclContextFindDeclByName (void *opaque_decl_ctx, ConstString name) override;
 
+    uint32_t
+    DeclContextCountDeclLevels (void *opaque_decl_ctx,
+                                void *opaque_find_decl_ctx,
+                                ConstString *find_name = nullptr,
+                                CompilerType *find_type = nullptr) override;
+
     bool
     DeclContextIsStructUnionOrClass (void *opaque_decl_ctx) override;
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to