Skip to content

Commit 9b045d5

Browse files
committed
Introduce a DWARFImporter delegate that can look up clang::Decls by name.
Traditionally a serialized binary Swift module (as used in debug info) can only be imported if all of its Clang dependencies can be imported *from source*. - Swift's ClangImporter imports Clang modules by converting Clang AST types into Swift AST types. - LLDB knows how to find Clang types in DWARF or other debug info and can synthesize a Clang AST from that information. This patch introduces a DWARFImporter delegate that is implemented by LLDB to connect these two components. With this, a Clang type can be found (by name) in the debug info and handed over to ClangImporter to create a Swift type from it. This path has lower fidelity than importing the Clang modules from source, since it is missing out on Swiftication annotations and other metadata that is not serialized in DWARF, but it's invaluable as a fallback mechanism for the debugger when source code for the Clang modules isn't available or the modules are otherwise not buildable. rdar://problem/49233932
1 parent eae8d02 commit 9b045d5

File tree

12 files changed

+261
-86
lines changed

12 files changed

+261
-86
lines changed

include/swift/AST/ASTContext.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,8 +639,10 @@ class ASTContext final {
639639
/// \param isClang \c true if this module loader is responsible for loading
640640
/// Clang modules, which are special-cased in some parts of the
641641
/// compiler.
642+
/// \param isDWARF \c true if this module loader can load Clang modules
643+
/// from DWARF.
642644
void addModuleLoader(std::unique_ptr<ModuleLoader> loader,
643-
bool isClang = false);
645+
bool isClang = false, bool isDWARF = false);
644646

645647
/// Load extensions to the given nominal type from the external
646648
/// module loaders.
@@ -683,6 +685,12 @@ class ASTContext final {
683685
/// The loader is owned by the AST context.
684686
ClangModuleLoader *getClangModuleLoader() const;
685687

688+
/// Retrieve the DWARF module loader for this ASTContext.
689+
///
690+
/// If there is no Clang module loader, returns a null pointer.
691+
/// The loader is owned by the AST context.
692+
ClangModuleLoader *getDWARFModuleLoader() const;
693+
686694
/// Asks every module loader to verify the ASTs it has loaded.
687695
///
688696
/// Does nothing in non-asserts (NDEBUG) builds.

include/swift/AST/ClangModuleLoader.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_AST_CLANG_MODULE_LOADER_H
1515

1616
#include "swift/AST/ModuleLoader.h"
17+
#include "swift/Demangling/Demangle.h"
1718

1819
namespace clang {
1920
class ASTContext;
@@ -25,6 +26,7 @@ class Sema;
2526
namespace swift {
2627

2728
class DeclContext;
29+
class VisibleDeclConsumer;
2830

2931
class ClangModuleLoader : public ModuleLoader {
3032
private:
@@ -58,6 +60,30 @@ class ClangModuleLoader : public ModuleLoader {
5860
const DeclContext *overlayDC,
5961
const DeclContext *importedDC) = 0;
6062

63+
/// Look for declarations associated with the given name.
64+
///
65+
/// \param name The name we're searching for.
66+
virtual void lookupValue(DeclName name, VisibleDeclConsumer &consumer) {}
67+
68+
/// Look up a type declaration by its Clang name.
69+
///
70+
/// Note that this method does no filtering. If it finds the type in a loaded
71+
/// module, it returns it. This is intended for use in reflection / debugging
72+
/// contexts where access is not a problem.
73+
virtual void lookupTypeDecl(StringRef clangName, Demangle::Node::Kind kind,
74+
llvm::function_ref<void(TypeDecl *)> receiver) {}
75+
76+
/// Look up type a declaration synthesized by the Clang importer itself, using
77+
/// a "related entity kind" to determine which type it should be. For example,
78+
/// this can be used to find the synthesized error struct for an
79+
/// NS_ERROR_ENUM.
80+
///
81+
/// Note that this method does no filtering. If it finds the type in a loaded
82+
/// module, it returns it. This is intended for use in reflection / debugging
83+
/// contexts where access is not a problem.
84+
virtual void
85+
lookupRelatedEntity(StringRef clangName, StringRef relatedEntityKind,
86+
llvm::function_ref<void(TypeDecl *)> receiver) {}
6187
};
6288

6389
} // namespace swift

include/swift/AST/ModuleLoader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class ClangImporterOptions;
3535
class ClassDecl;
3636
class ModuleDecl;
3737
class NominalTypeDecl;
38+
class TypeDecl;
3839

3940
enum class KnownProtocolKind : uint8_t;
4041

include/swift/ClangImporter/ClangImporter.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ enum class ClangTypeKind {
7575
/// from Clang ASTs over to Swift ASTs.
7676
class ClangImporter final : public ClangModuleLoader {
7777
friend class ClangModuleUnit;
78+
friend class DWARFImporter;
7879

7980
public:
8081
class Implementation;
@@ -160,15 +161,15 @@ class ClangImporter final : public ClangModuleLoader {
160161
/// Look for declarations associated with the given name.
161162
///
162163
/// \param name The name we're searching for.
163-
void lookupValue(DeclName name, VisibleDeclConsumer &consumer);
164+
void lookupValue(DeclName name, VisibleDeclConsumer &consumer) override;
164165

165166
/// Look up a type declaration by its Clang name.
166167
///
167168
/// Note that this method does no filtering. If it finds the type in a loaded
168169
/// module, it returns it. This is intended for use in reflection / debugging
169170
/// contexts where access is not a problem.
170-
void lookupTypeDecl(StringRef clangName, ClangTypeKind kind,
171-
llvm::function_ref<void(TypeDecl*)> receiver);
171+
void lookupTypeDecl(StringRef clangName, Demangle::Node::Kind kind,
172+
llvm::function_ref<void(TypeDecl*)> receiver) override;
172173

173174
/// Look up type a declaration synthesized by the Clang importer itself, using
174175
/// a "related entity kind" to determine which type it should be. For example,
@@ -178,9 +179,9 @@ class ClangImporter final : public ClangModuleLoader {
178179
/// Note that this method does no filtering. If it finds the type in a loaded
179180
/// module, it returns it. This is intended for use in reflection / debugging
180181
/// contexts where access is not a problem.
181-
void lookupRelatedEntity(StringRef clangName, ClangTypeKind kind,
182-
StringRef relatedEntityKind,
183-
llvm::function_ref<void(TypeDecl*)> receiver);
182+
void
183+
lookupRelatedEntity(StringRef clangName, StringRef relatedEntityKind,
184+
llvm::function_ref<void(TypeDecl *)> receiver) override;
184185

185186
/// Look for textually included declarations from the bridging header.
186187
///

include/swift/DWARFImporter/DWARFImporter.h

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define SWIFT_DWARF_IMPORTER_H
1919

2020
#include "swift/AST/ClangModuleLoader.h"
21+
#include "swift/AST/Module.h"
22+
#include "swift/Demangling/Demangle.h"
2123

2224
namespace llvm {
2325
}
@@ -27,6 +29,25 @@ namespace clang {
2729

2830
namespace swift {
2931

32+
/// This interface is implemented by LLDB to serve as a fallback when Clang
33+
/// modules can't be imported from source in the debugger.
34+
///
35+
/// During compile time, ClangImporter-imported Clang modules are compiled with
36+
/// -gmodules, which emits a DWARF rendition of all types defined in the module
37+
/// into the .pcm file. On Darwin, these types can be collected by
38+
/// dsymutil. This delegate allows DWARFImporter to ask LLDB to look up a Clang
39+
/// type by name, synthesize a Clang AST from it. DWARFImporter then hands this
40+
/// Clang AST to ClangImporter to import the type into Swift.
41+
class DWARFImporterDelegate {
42+
public:
43+
virtual ~DWARFImporterDelegate() {}
44+
/// Perform a qualified lookup of a Clang type with this name.
45+
/// \param kind Only return results with this type kind.
46+
virtual void lookupValue(StringRef name,
47+
llvm::Optional<Demangle::Node::Kind> kind,
48+
SmallVectorImpl<clang::Decl *> &results) {}
49+
};
50+
3051
/// Class that imports Clang modules into Swift, mapping directly
3152
/// from Clang ASTs over to Swift ASTs.
3253
class DWARFImporter final : public ClangModuleLoader {
@@ -39,6 +60,7 @@ class DWARFImporter final : public ClangModuleLoader {
3960
Implementation &Impl;
4061

4162
DWARFImporter(ASTContext &ctx, const ClangImporterOptions &clangImporterOpts,
63+
std::unique_ptr<DWARFImporterDelegate> delegate,
4264
DependencyTracker *tracker);
4365

4466
public:
@@ -55,8 +77,8 @@ class DWARFImporter final : public ClangModuleLoader {
5577
/// \returns a new DWARF module importer, or null (with a diagnostic) if
5678
/// an error occurred.
5779
static std::unique_ptr<DWARFImporter>
58-
create(ASTContext &ctx,
59-
const ClangImporterOptions &importerOpts,
80+
create(ASTContext &ctx, const ClangImporterOptions &importerOpts,
81+
std::unique_ptr<DWARFImporterDelegate> delegate = {},
6082
DependencyTracker *tracker = nullptr);
6183

6284
DWARFImporter(const DWARFImporter &) = delete;
@@ -80,6 +102,17 @@ class DWARFImporter final : public ClangModuleLoader {
80102
ModuleDecl *
81103
loadModule(SourceLoc importLoc,
82104
ArrayRef<std::pair<Identifier, SourceLoc>> path) override;
105+
106+
ValueDecl *importDecl(clang::Decl *clangDecl);
107+
108+
void lookupValue(DeclName name, VisibleDeclConsumer &consumer) override {}
109+
/// Behaves like \p ClangImporter::lookupValue.
110+
void lookupValue(ModuleDecl::AccessPathTy accessPath, DeclName name,
111+
NLKind lookupKind, SmallVectorImpl<ValueDecl *> &results);
112+
/// Perform a qualified lookup of a Clang type with this name and only return
113+
/// results with the specified type kind.
114+
void lookupTypeDecl(StringRef rawName, Demangle::Node::Kind kind,
115+
llvm::function_ref<void(TypeDecl *)> receiver) override;
83116
bool
84117
isInOverlayModuleForImportedModule(const DeclContext *overlayDC,
85118
const DeclContext *importedDC) override;

lib/AST/ASTContext.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
255255
/// The module loader used to load Clang modules.
256256
ClangModuleLoader *TheClangModuleLoader = nullptr;
257257

258+
/// The module loader used to load Clang modules from DWARF.
259+
ClangModuleLoader *TheDWARFModuleLoader = nullptr;
260+
258261
/// Map from Swift declarations to raw comments.
259262
llvm::DenseMap<const Decl *, RawComment> RawComments;
260263

@@ -1446,10 +1449,13 @@ void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
14461449
}
14471450

14481451
void ASTContext::addModuleLoader(std::unique_ptr<ModuleLoader> loader,
1449-
bool IsClang) {
1450-
if (IsClang && !getImpl().TheClangModuleLoader)
1452+
bool IsClang, bool IsDwarf) {
1453+
if (IsClang && !IsDwarf && !getImpl().TheClangModuleLoader)
14511454
getImpl().TheClangModuleLoader =
14521455
static_cast<ClangModuleLoader *>(loader.get());
1456+
if (IsClang && IsDwarf && !getImpl().TheDWARFModuleLoader)
1457+
getImpl().TheDWARFModuleLoader =
1458+
static_cast<ClangModuleLoader *>(loader.get());
14531459

14541460
getImpl().ModuleLoaders.push_back(std::move(loader));
14551461
}
@@ -1493,6 +1499,10 @@ ClangModuleLoader *ASTContext::getClangModuleLoader() const {
14931499
return getImpl().TheClangModuleLoader;
14941500
}
14951501

1502+
ClangModuleLoader *ASTContext::getDWARFModuleLoader() const {
1503+
return getImpl().TheDWARFModuleLoader;
1504+
}
1505+
14961506
ModuleDecl *ASTContext::getLoadedModule(
14971507
ArrayRef<std::pair<Identifier, SourceLoc>> ModulePath) const {
14981508
assert(!ModulePath.empty());

lib/AST/ASTDemangler.cpp

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
#include "swift/AST/ASTDemangler.h"
2323

2424
#include "swift/AST/ASTContext.h"
25+
#include "swift/AST/ClangModuleLoader.h"
2526
#include "swift/AST/Decl.h"
2627
#include "swift/AST/GenericSignature.h"
2728
#include "swift/AST/GenericSignatureBuilder.h"
2829
#include "swift/AST/Module.h"
2930
#include "swift/AST/NameLookup.h"
3031
#include "swift/AST/Type.h"
3132
#include "swift/AST/Types.h"
32-
#include "swift/ClangImporter/ClangImporter.h"
3333
#include "swift/Demangling/Demangler.h"
3434
#include "swift/Demangling/ManglingMacros.h"
3535

@@ -1023,31 +1023,14 @@ ASTBuilder::findTypeDecl(DeclContext *dc,
10231023
return result;
10241024
}
10251025

1026-
static Optional<ClangTypeKind>
1027-
getClangTypeKindForNodeKind(Demangle::Node::Kind kind) {
1028-
switch (kind) {
1029-
case Demangle::Node::Kind::Protocol:
1030-
return ClangTypeKind::ObjCProtocol;
1031-
case Demangle::Node::Kind::Class:
1032-
return ClangTypeKind::ObjCClass;
1033-
case Demangle::Node::Kind::TypeAlias:
1034-
return ClangTypeKind::Typedef;
1035-
case Demangle::Node::Kind::Structure:
1036-
case Demangle::Node::Kind::Enum:
1037-
return ClangTypeKind::Tag;
1038-
default:
1039-
return None;
1040-
}
1041-
}
1042-
1043-
GenericTypeDecl *
1044-
ASTBuilder::findForeignTypeDecl(StringRef name,
1045-
StringRef relatedEntityKind,
1046-
ForeignModuleKind foreignKind,
1047-
Demangle::Node::Kind kind) {
1026+
GenericTypeDecl *ASTBuilder::findForeignTypeDecl(StringRef name,
1027+
StringRef relatedEntityKind,
1028+
ForeignModuleKind foreignKind,
1029+
Demangle::Node::Kind kind) {
10481030
// Check to see if we have an importer loaded.
1049-
auto importer = static_cast<ClangImporter *>(Ctx.getClangModuleLoader());
1050-
if (!importer) return nullptr;
1031+
auto importer = Ctx.getClangModuleLoader();
1032+
if (!importer)
1033+
return nullptr;
10511034

10521035
// Find the unique declaration that has the right kind.
10531036
struct Consumer : VisibleDeclConsumer {
@@ -1059,8 +1042,10 @@ ASTBuilder::findForeignTypeDecl(StringRef name,
10591042

10601043
void foundDecl(ValueDecl *decl, DeclVisibilityKind reason,
10611044
DynamicLookupInfo dynamicLookupInfo = {}) override {
1062-
if (HadError) return;
1063-
if (decl == Result) return;
1045+
if (HadError)
1046+
return;
1047+
if (decl == Result)
1048+
return;
10641049
if (!Result) {
10651050
Result = dyn_cast<GenericTypeDecl>(decl);
10661051
HadError |= !Result;
@@ -1071,33 +1056,27 @@ ASTBuilder::findForeignTypeDecl(StringRef name,
10711056
}
10721057
} consumer(kind);
10731058

1059+
auto found = [&](TypeDecl *found) {
1060+
consumer.foundDecl(found, DeclVisibilityKind::VisibleAtTopLevel);
1061+
};
1062+
10741063
switch (foreignKind) {
10751064
case ForeignModuleKind::SynthesizedByImporter:
10761065
if (!relatedEntityKind.empty()) {
1077-
Optional<ClangTypeKind> lookupKind = getClangTypeKindForNodeKind(kind);
1078-
if (!lookupKind)
1079-
return nullptr;
1080-
importer->lookupRelatedEntity(name, lookupKind.getValue(),
1081-
relatedEntityKind, [&](TypeDecl *found) {
1082-
consumer.foundDecl(found, DeclVisibilityKind::VisibleAtTopLevel);
1083-
});
1066+
importer->lookupRelatedEntity(name, relatedEntityKind, found);
10841067
break;
10851068
}
10861069
importer->lookupValue(Ctx.getIdentifier(name), consumer);
1087-
if (consumer.Result) {
1088-
consumer.Result =
1089-
getAcceptableTypeDeclCandidate(consumer.Result,kind);
1090-
}
1070+
if (consumer.Result)
1071+
consumer.Result = getAcceptableTypeDeclCandidate(consumer.Result, kind);
10911072
break;
1092-
case ForeignModuleKind::Imported: {
1093-
Optional<ClangTypeKind> lookupKind = getClangTypeKindForNodeKind(kind);
1094-
if (!lookupKind)
1095-
return nullptr;
1096-
importer->lookupTypeDecl(name, lookupKind.getValue(),
1097-
[&](TypeDecl *found) {
1098-
consumer.foundDecl(found, DeclVisibilityKind::VisibleAtTopLevel);
1099-
});
1100-
}
1073+
case ForeignModuleKind::Imported:
1074+
importer->lookupTypeDecl(name, kind, found);
1075+
1076+
// Try the DWARFImporter if it exists.
1077+
if (!consumer.Result)
1078+
if (auto *dwarf_importer = Ctx.getDWARFModuleLoader())
1079+
dwarf_importer->lookupTypeDecl(name, kind, found);
11011080
}
11021081

11031082
return consumer.Result;

0 commit comments

Comments
 (0)