Skip to content

Commit 2aeef9e

Browse files
handle clang module export statements in SymbolGraphGen
1 parent 8156307 commit 2aeef9e

File tree

3 files changed

+113
-13
lines changed

3 files changed

+113
-13
lines changed

lib/SymbolGraphGen/SymbolGraphGen.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,23 +63,43 @@ int symbolgraphgen::emitSymbolGraphForModule(
6363
ModuleDecl *M, const SymbolGraphOptions &Options) {
6464
ModuleDecl::ImportCollector importCollector(Options.MinimumAccessLevel);
6565

66-
bool IncludeClangSubmodules = false;
67-
if (auto *ClangModule = M->findUnderlyingClangModule()) {
68-
// If a Clang module has a definition that includes `export *; module * {
69-
// export *; }` then we want to treat those inferred submodules as part of
70-
// the parent module, to preserve historical behavior.
71-
if (ClangModule->InferSubmodules && ClangModule->InferExportWildcard) {
72-
IncludeClangSubmodules = true;
66+
SmallPtrSet<const clang::Module *, 2> ExportedClangModules = {};
67+
SmallPtrSet<const clang::Module *, 2> WildcardExportClangModules = {};
68+
if (const auto *ClangModule = M->findUnderlyingClangModule()) {
69+
// Scan through the Clang module's exports and collect them for later
70+
// handling
71+
for (auto ClangExport : ClangModule->Exports) {
72+
if (ClangExport.getInt()) {
73+
// Blanket exports are represented as a true boolean tag
74+
if (const auto *ExportParent = ClangExport.getPointer()) {
75+
// If a pointer is present, this is a scoped blanket export, like
76+
// `export Submodule.*`
77+
WildcardExportClangModules.insert(ExportParent);
78+
} else {
79+
// Otherwise it represents a full blanket `export *`
80+
WildcardExportClangModules.insert(ClangModule);
81+
}
82+
} else if (!ClangExport.getInt() && ClangExport.getPointer()) {
83+
// This is an explicit `export Submodule`
84+
ExportedClangModules.insert(ClangExport.getPointer());
85+
}
7386
}
7487
}
7588

76-
auto importFilter = [&Options, &IncludeClangSubmodules,
77-
&M](const ModuleDecl *module) {
89+
auto importFilter = [&Options, &WildcardExportClangModules,
90+
&ExportedClangModules](const ModuleDecl *module) {
7891
if (!module)
7992
return false;
8093

81-
if (IncludeClangSubmodules && module->isSubmoduleOf(M)) {
82-
return true;
94+
if (const auto *ClangModule = module->findUnderlyingClangModule()) {
95+
if (ExportedClangModules.contains(ClangModule)) {
96+
return true;
97+
}
98+
99+
for (const auto *ClangParent : WildcardExportClangModules) {
100+
if (ClangModule->isSubModuleOf(ClangParent))
101+
return true;
102+
}
83103
}
84104

85105
if (Options.AllowedReexportedModules.has_value())
@@ -90,7 +110,8 @@ int symbolgraphgen::emitSymbolGraphForModule(
90110
return false;
91111
};
92112

93-
if (Options.AllowedReexportedModules.has_value() || IncludeClangSubmodules)
113+
if (Options.AllowedReexportedModules.has_value() ||
114+
!WildcardExportClangModules.empty() || !ExportedClangModules.empty())
94115
importCollector.importFilter = std::move(importFilter);
95116

96117
SmallVector<Decl *, 64> ModuleDecls;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: split-file %s %t
4+
5+
// RUN: %target-swift-symbolgraph-extract -sdk %clang-importer-sdk -module-name PartialSubmoduleExport -I %t/PartialSubmoduleExport -output-dir %t -pretty-print -v
6+
// RUN: %FileCheck %s --input-file %t/PartialSubmoduleExport.symbols.json
7+
8+
// REQUIRES: objc_interop
9+
10+
// The PartialSubmoduleExport module below is structured like this:
11+
12+
// PartialSubmoduleExport
13+
// - GroupA
14+
// - GroupAOne
15+
// - GroupATwo
16+
// - GroupB
17+
// - GroupBOne
18+
// - GroupBTwo
19+
20+
// The module map then exports `GroupA.*` and `GroupB.GroupBOne` explicitly.
21+
// This test ensures that the expected symbols are in the module map,
22+
// and that the deliberately excluded `groupBTwo` symbol is left out.
23+
24+
//--- PartialSubmoduleExport/module.modulemap
25+
module PartialSubmoduleExport {
26+
header "PartialSubmoduleExport.h"
27+
28+
explicit module GroupA {
29+
umbrella header "GroupA/GroupA.h"
30+
31+
module * { export * }
32+
}
33+
34+
explicit module GroupB {
35+
umbrella header "GroupB/GroupB.h"
36+
37+
module * { export * }
38+
}
39+
40+
export GroupA.*
41+
export GroupB.GroupBOne
42+
}
43+
44+
//--- PartialSubmoduleExport/PartialSubmoduleExport.h
45+
#include "GroupA/GroupA.h"
46+
#include "GroupB/GroupB.h"
47+
48+
// CHECK-DAG: "precise": "c:PartialSubmoduleExport.h@umbrellaVar"
49+
static int umbrellaVar = 0;
50+
51+
//--- PartialSubmoduleExport/GroupA/GroupA.h
52+
#include "GroupAOne.h"
53+
#include "GroupATwo.h"
54+
55+
// CHECK-DAG: "precise": "c:GroupA.h@groupAVar"
56+
static int groupAVar = 0;
57+
58+
//--- PartialSubmoduleExport/GroupA/GroupAOne.h
59+
// CHECK-DAG: "precise": "c:GroupAOne.h@groupAOne"
60+
static int groupAOne = 1;
61+
62+
//--- PartialSubmoduleExport/GroupA/GroupATwo.h
63+
// CHECK-DAG: "precise": "c:GroupATwo.h@groupATwo"
64+
static int groupATwo = 2;
65+
66+
//--- PartialSubmoduleExport/GroupB/GroupB.h
67+
#include "GroupBOne.h"
68+
#include "GroupBTwo.h"
69+
70+
static int groupBVar = 0;
71+
72+
//--- PartialSubmoduleExport/GroupB/GroupBOne.h
73+
// CHECK-DAG: "precise": "c:GroupBOne.h@groupBOne"
74+
static int groupBOne = 1;
75+
76+
//--- PartialSubmoduleExport/GroupB/GroupBTwo.h
77+
// Because GroupBTwo is not exported in the top-level module map,
78+
// this shouldn't be in the symbol graph
79+
// CHECK-NOT: "precise": "c:GroupBTwo.h@groupBTwo"
80+
static int groupBTwo = 2;

test/SymbolGraph/ClangImporter/UmbrellaSubmodules.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %empty-directory(%t/SwiftAttr)
43
// RUN: split-file %s %t
54

65
// RUN: %target-swift-symbolgraph-extract -sdk %clang-importer-sdk -module-name UmbrellaSubmodules -I %t/UmbrellaSubmodules -output-dir %t -pretty-print -v

0 commit comments

Comments
 (0)