Skip to content

Commit 15bb8ec

Browse files
committed
[lldb] Handle @_originallyDefinedIn
Types annotated with @_originallyDefinedIn don't live in the module listed in their mangled name. To account for this, the compiler emits a DW_TAG_imported_declaration for those types under the name of the swiftmodule these types can be found at. This patch implements the logic required to produce the mangled name that can be used in type reconstruction to successfully find these types. rdar://137146961 (cherry picked from commit ce1a9d5)
1 parent a341929 commit 15bb8ec

File tree

7 files changed

+433
-4
lines changed

7 files changed

+433
-4
lines changed

lldb/source/Plugins/TypeSystem/Swift/SwiftASTContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4772,6 +4772,16 @@ SwiftASTContext::ReconstructType(ConstString mangled_typename) {
47724772
.getPointer();
47734773
assert(!found_type || &found_type->getASTContext() == *ast_ctx);
47744774

4775+
// This type might have been been found in reflection and annotated with
4776+
// @_originallyDefinedIn. The compiler emits a typelias for these type
4777+
// pointing them back to the types with the real module name.
4778+
if (!found_type) {
4779+
auto adjusted =
4780+
GetTypeSystemSwiftTypeRef()->AdjustTypeForOriginallyDefinedInModule(
4781+
mangled_typename);
4782+
found_type =
4783+
swift::Demangle::getTypeForMangling(**ast_ctx, adjusted).getPointer();
4784+
}
47754785
// Objective-C classes sometimes have private subclasses that are invisible
47764786
// to the Swift compiler because they are declared and defined in a .m file.
47774787
// If we can't reconstruct an ObjC type, walk up the type hierarchy until we

lldb/source/Plugins/TypeSystem/Swift/SwiftDemangle.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,23 @@ NodeAtPath(swift::Demangle::NodePointer root,
5959
return ChildAtPath(root, kind_path.drop_front());
6060
}
6161

62-
/// \return the child of the \p Type node.
63-
static swift::Demangle::NodePointer GetType(swift::Demangle::NodePointer n) {
62+
/// \return the child of the TypeMangling node.
63+
static swift::Demangle::NodePointer
64+
GetTypeMangling(swift::Demangle::NodePointer n) {
6465
using namespace swift::Demangle;
6566
if (!n || n->getKind() != Node::Kind::Global)
6667
return nullptr;
6768
n = n->getFirstChild();
6869
if (!n || n->getKind() != Node::Kind::TypeMangling || !n->hasChildren())
6970
return nullptr;
7071
n = n->getFirstChild();
72+
return n;
73+
}
74+
75+
/// \return the child of the \p Type node.
76+
static swift::Demangle::NodePointer GetType(swift::Demangle::NodePointer n) {
77+
using namespace swift::Demangle;
78+
n = GetTypeMangling(n);
7179
if (!n || n->getKind() != Node::Kind::Type || !n->hasChildren())
7280
return nullptr;
7381
n = n->getFirstChild();
@@ -80,6 +88,14 @@ GetDemangledType(swift::Demangle::Demangler &dem, llvm::StringRef name) {
8088
return GetType(dem.demangleSymbol(name));
8189
}
8290

91+
/// Demangle a mangled type name and return the child of the \p TypeMangling
92+
/// node.
93+
inline swift::Demangle::NodePointer
94+
GetDemangledTypeMangling(swift::Demangle::Demangler &dem,
95+
llvm::StringRef name) {
96+
return GetTypeMangling(dem.demangleSymbol(name));
97+
}
98+
8399
/// Wrap node in Global/TypeMangling/Type.
84100
static swift::Demangle::NodePointer
85101
mangleType(swift::Demangle::Demangler &dem,

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.cpp

Lines changed: 176 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636

3737
#include "swift/ClangImporter/ClangImporter.h"
3838
#include "swift/../../lib/ClangImporter/ClangAdapter.h"
39+
#include "swift/Demangling/Demangle.h"
40+
#include "swift/Demangling/Demangler.h"
3941
#include "swift/Frontend/Frontend.h"
4042

4143
#include "clang/APINotes/APINotesManager.h"
@@ -150,6 +152,178 @@ TypeSystemSwiftTypeRef::CanonicalizeSugar(swift::Demangle::Demangler &dem,
150152
});
151153
}
152154

155+
NodePointer TypeSystemSwiftTypeRef::FindTypeWithModuleAndIdentifierNode(
156+
swift::Demangle::NodePointer node) {
157+
if (!node || node->getKind() != Node::Kind::Type)
158+
return nullptr;
159+
160+
NodePointer current = node;
161+
while (current && current->hasChildren() &&
162+
current->getFirstChild()->getKind() != Node::Kind::Module) {
163+
current = current->getFirstChild();
164+
}
165+
switch (current->getKind()) {
166+
case Node::Kind::Structure:
167+
case Node::Kind::Class:
168+
case Node::Kind::Enum:
169+
case Node::Kind::BoundGenericStructure:
170+
case Node::Kind::BoundGenericClass:
171+
case Node::Kind::BoundGenericEnum:
172+
return current;
173+
default:
174+
return nullptr;
175+
}
176+
}
177+
178+
std::string TypeSystemSwiftTypeRef::AdjustTypeForOriginallyDefinedInModule(
179+
llvm::StringRef mangled_typename) {
180+
if (mangled_typename.empty())
181+
return {};
182+
183+
swift::Demangle::Demangler dem;
184+
auto *type_node =
185+
swift_demangle::GetDemangledTypeMangling(dem, mangled_typename);
186+
if (!type_node)
187+
return {};
188+
189+
TargetSP target_sp(GetTargetWP().lock());
190+
if (!target_sp)
191+
return {};
192+
193+
ModuleList &module_list = target_sp->GetImages();
194+
195+
// A map from the node containing the module and identifier of a specific type
196+
// to a node with the modified module and identifier of that type. For
197+
// example, given the following type:
198+
//
199+
// Module "a":
200+
//
201+
// @available(...)
202+
// @_originallyDefinedIn(module: "Other", ...)
203+
// public struct A { ... }
204+
// The demangle tree of the mangled name stored in DWARF will be:
205+
//
206+
// kind=Global
207+
// kind=TypeMangling
208+
// kind=Type
209+
// kind=Structure
210+
// kind=Module, text="Other"
211+
// kind=Identifier, text="A"
212+
//
213+
// This functions needs to construct the following tree:
214+
//
215+
// kind=Global
216+
// kind=TypeMangling
217+
// kind=Type
218+
// kind=Structure
219+
// kind=Module, text="a"
220+
// kind=Identifier, text="A"
221+
//
222+
// type_to_renamed_type_nodes is populated with the nodes in the original tree
223+
// node that need to be replaced mapping to their replacements. In this
224+
// example that would be:
225+
//
226+
// kind=Structure
227+
// kind=Module, text="Other"
228+
// kind=Identifier, text="A"
229+
//
230+
// mapping to:
231+
//
232+
// kind=Structure
233+
// kind=Module, text="a"
234+
// kind=Identifier, text="A"
235+
//
236+
// We can't have a map from module nodes to renamed module nodes because those
237+
// nodes might be reused elsewhere in the tree.
238+
llvm::DenseMap<NodePointer, NodePointer> type_to_renamed_type_nodes;
239+
240+
// Visit the demangle tree and populate type_to_renamed_type_nodes.
241+
PreOrderTraversal(type_node, [&](NodePointer node) {
242+
// We're visiting the entire tree, but we only need to examine "Type" nodes.
243+
if (node->getKind() != Node::Kind::Type)
244+
return true;
245+
246+
auto compiler_type = RemangleAsType(dem, node);
247+
if (!compiler_type)
248+
return true;
249+
250+
// Find the node that contains the module and identifier nodes.
251+
NodePointer node_with_module_and_name =
252+
FindTypeWithModuleAndIdentifierNode(node);
253+
if (!node_with_module_and_name)
254+
return true;
255+
256+
auto module_name = node_with_module_and_name->getFirstChild()->getText();
257+
// Clang types couldn't have been renamed.
258+
if (module_name == swift::MANGLING_MODULE_OBJC)
259+
return true;
260+
261+
// If we already processed this node there's nothing to do (this can happen
262+
// because nodes are shared in the tree).
263+
if (type_to_renamed_type_nodes.contains(node_with_module_and_name))
264+
return true;
265+
266+
// Look for the imported declarations that indicate the type has moved
267+
// modules.
268+
std::vector<ImportedDeclaration> decls;
269+
module_list.FindImportedDeclarations(GetModule(),
270+
compiler_type.GetMangledTypeName(),
271+
decls, /*find_one=*/true);
272+
// If there are none there's nothing to do.
273+
if (decls.empty())
274+
return true;
275+
276+
std::vector<lldb_private::CompilerContext> declContext =
277+
decls[0].GetDeclContext();
278+
279+
lldbassert(!declContext.empty() &&
280+
"Unexpected decl context for imported declaration!");
281+
if (declContext.empty())
282+
return true;
283+
284+
auto module_context = declContext[0];
285+
286+
// If the mangled name's module and module context module match then
287+
// there's nothing to do.
288+
if (module_name == module_context.name)
289+
return true;
290+
291+
// Construct the node tree that will substituted in.
292+
NodePointer new_node = dem.createNode(node_with_module_and_name->getKind());
293+
NodePointer new_module_node = dem.createNodeWithAllocatedText(
294+
Node::Kind::Module, module_context.name);
295+
new_node->addChild(new_module_node, dem);
296+
new_node->addChild(node_with_module_and_name->getLastChild(), dem);
297+
298+
type_to_renamed_type_nodes[node_with_module_and_name] = new_node;
299+
return true;
300+
});
301+
302+
// If there are no renamed modules, there's nothing to do.
303+
if (type_to_renamed_type_nodes.empty())
304+
return mangled_typename.str();
305+
306+
NodePointer transformed = Transform(dem, type_node, [&](NodePointer node) {
307+
return type_to_renamed_type_nodes.contains(node)
308+
? type_to_renamed_type_nodes[node]
309+
: node;
310+
});
311+
312+
auto mangling = mangleNode(swift_demangle::mangleType(dem, transformed));
313+
assert(mangling.isSuccess());
314+
if (!mangling.isSuccess()) {
315+
LLDB_LOG(GetLog(LLDBLog::Types),
316+
"[AdjustTypeForOriginallyDefinedInModule] Unexpected mangling "
317+
"error when mangling adjusted node for type with mangled name {0}",
318+
mangled_typename);
319+
320+
return {};
321+
}
322+
323+
auto str = mangling.result();
324+
return str;
325+
}
326+
153327
llvm::StringRef
154328
TypeSystemSwiftTypeRef::GetBaseName(swift::Demangle::NodePointer node) {
155329
if (!node)
@@ -230,7 +404,7 @@ TypeSP TypeSystemSwiftTypeRefForExpressions::LookupClangType(
230404
ConstString name(name_ref);
231405
if (m_clang_type_cache.Lookup(name.AsCString(), result))
232406
return result;
233-
407+
234408
TargetSP target_sp = GetTargetWP().lock();
235409
if (!target_sp)
236410
return {};
@@ -446,7 +620,7 @@ TypeSystemSwiftTypeRef::GetClangTypeNode(CompilerType clang_type,
446620
if (!is_vector)
447621
break;
448622

449-
auto qual_type = ClangUtil::GetQualType(clang_type);
623+
auto qual_type = ClangUtil::GetQualType(clang_type);
450624
const auto *ptr = qual_type.getTypePtrOrNull();
451625
if (!ptr)
452626
break;

lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwiftTypeRef.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,20 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift {
370370
CanonicalizeSugar(swift::Demangle::Demangler &dem,
371371
swift::Demangle::NodePointer node);
372372

373+
/// Finds the nominal type node (struct, class, enum) that contains the
374+
/// module and identifier nodes for that type. If \p node is not a valid
375+
/// type node, returns a nullptr.
376+
static swift::Demangle::NodePointer
377+
FindTypeWithModuleAndIdentifierNode(swift::Demangle::NodePointer node);
378+
379+
/// Types with the @_originallyDefinedIn attribute are serialized with with
380+
/// the original module name in reflection metadata. At the same time the type
381+
/// is serialized with the swiftmodule name in debug info, but with a parent
382+
/// module with the original module name. This function adjusts \type to look
383+
/// up the type in reflection metadata if necessary.
384+
std::string
385+
AdjustTypeForOriginallyDefinedInModule(llvm::StringRef mangled_typename);
386+
373387
/// Return the canonicalized Demangle tree for a Swift mangled type name.
374388
swift::Demangle::NodePointer
375389
GetCanonicalDemangleTree(swift::Demangle::Demangler &dem,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
include Makefile.rules
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import os
2+
import lldb
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbtest as lldbtest
5+
import lldbsuite.test.lldbutil as lldbutil
6+
7+
8+
class TestSwiftOriginallyDefinedIn(lldbtest.TestBase):
9+
@swiftTest
10+
def test(self):
11+
"""Test that types with the @_originallyDefinedIn attribute can still be found in metadata"""
12+
13+
self.build()
14+
self.runCmd("setting set symbols.swift-enable-ast-context false")
15+
filespec = lldb.SBFileSpec("main.swift")
16+
target, process, thread, breakpoint1 = lldbutil.run_to_source_breakpoint(
17+
self, "break here", filespec
18+
)
19+
self.expect("frame variable a", substrs=["a = (i = 10)"])
20+
self.expect("frame variable b", substrs=["b = (i = 20)"])
21+
self.expect("frame variable d", substrs=["d = (i = 30)"])
22+
self.expect("frame variable e", substrs=["i = 50"])
23+
self.expect("frame variable f", substrs=["i = 40"])
24+
self.expect("frame variable g", substrs=["i = 60"])
25+
self.expect("frame variable h", substrs=["t = (i = 50)", "u = (i = 70)"])
26+
self.expect("frame variable i", substrs=["(i = 10)", "(i = 40)", "(i = 50)"])
27+
self.expect(
28+
"frame variable complex",
29+
substrs=[
30+
"t = t {",
31+
"t = {",
32+
"t = (i = 70)",
33+
"u = (i = 30)",
34+
"u = t {",
35+
"t = (i = 50)",
36+
],
37+
)
38+
39+
@swiftTest
40+
def test_expr(self):
41+
"""Test that types with the @_originallyDefinedIn attribute can still be found in metadata"""
42+
43+
self.build()
44+
filespec = lldb.SBFileSpec("main.swift")
45+
target, process, thread, breakpoint1 = lldbutil.run_to_source_breakpoint(
46+
self, "break here", filespec
47+
)
48+
self.expect("expr a", substrs=["(i = 10)"])
49+
self.expect("expr b", substrs=["(i = 20)"])
50+
self.expect("expr d", substrs=["(i = 30)"])
51+
self.expect("expr e", substrs=["(i = 50)"])
52+
self.expect("expr f", substrs=["i = 40"])
53+
self.expect("expr g", substrs=["i = 60"])
54+
self.expect("expr i", substrs=["(i = 10)", "(i = 40)", "(i = 50)"])
55+
self.expect(
56+
"expr complex",
57+
substrs=[
58+
"t = t {",
59+
"t = {",
60+
"t = (i = 70)",
61+
"u = (i = 30)",
62+
"u = t {",
63+
"t = (i = 50)",
64+
],
65+
)
66+
67+
@swiftTest
68+
def test_expr_from_generic(self):
69+
"""Test that types with the @_originallyDefinedIn attribute can still be found in metadata"""
70+
71+
self.build()
72+
filespec = lldb.SBFileSpec("main.swift")
73+
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
74+
self, "break for generic", filespec
75+
)
76+
self.expect("expr t", substrs=["(i = 10)"])
77+
lldbutil.continue_to_breakpoint(process, bkpt)
78+
self.expect("expr t", substrs=["(i = 20)"])
79+
lldbutil.continue_to_breakpoint(process, bkpt)
80+
self.expect("expr t", substrs=["(i = 30)"])
81+
lldbutil.continue_to_breakpoint(process, bkpt)
82+
self.expect("expr t", substrs=["(i = 50)"])
83+
lldbutil.continue_to_breakpoint(process, bkpt)
84+
self.expect("expr t", substrs=["(i = 40)"])
85+
lldbutil.continue_to_breakpoint(process, bkpt)
86+
self.expect("expr t", substrs=["(i = 60)"])
87+
lldbutil.continue_to_breakpoint(process, bkpt)
88+
self.expect("expr t", substrs=["t = (i = 50)", "u = (i = 70)"])
89+
lldbutil.continue_to_breakpoint(process, bkpt)
90+
self.expect("expr t", substrs=["(i = 10)", "(i = 40)", "(i = 50)"])
91+
lldbutil.continue_to_breakpoint(process, bkpt)
92+
self.expect(
93+
"expr t",
94+
substrs=[
95+
"t = t {",
96+
"t = {",
97+
"t = (i = 70)",
98+
"u = (i = 30)",
99+
"u = t {",
100+
"t = (i = 50)",
101+
],
102+
)

0 commit comments

Comments
 (0)