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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits