Skip to content

Commit 1a47da0

Browse files
authored
Add minimum access level as a setting for the symbol graph extraction (#792)
* Add minimum access level as a setting for the symbol graph extraction * Add minimum access level enum to PropertyDomainSpec * Add test coverage for new docc build settings
1 parent f0ba164 commit 1a47da0

File tree

5 files changed

+116
-11
lines changed

5 files changed

+116
-11
lines changed

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,7 @@ public final class BuiltinMacros {
10991099
public static let DOCC_ARCHIVE_PATH = BuiltinMacros.declareStringMacro("DOCC_ARCHIVE_PATH")
11001100
public static let DOCC_PRETTY_PRINT = BuiltinMacros.declareBooleanMacro("DOCC_PRETTY_PRINT")
11011101
public static let DOCC_EXTRACT_SPI_DOCUMENTATION = BuiltinMacros.declareBooleanMacro("DOCC_EXTRACT_SPI_DOCUMENTATION")
1102+
public static let DOCC_MINIMUM_ACCESS_LEVEL = BuiltinMacros.declareEnumMacro("DOCC_MINIMUM_ACCESS_LEVEL") as EnumMacroDeclaration<DoccMinimumAccessLevel>
11021103
public static let DOCC_SKIP_SYNTHESIZED_MEMBERS = BuiltinMacros.declareBooleanMacro("DOCC_SKIP_SYNTHESIZED_MEMBERS")
11031104
public static let DOCC_EXTRACT_EXTENSION_SYMBOLS = BuiltinMacros.declareBooleanMacro("DOCC_EXTRACT_EXTENSION_SYMBOLS")
11041105
public static let DOCC_EXTRACT_SWIFT_INFO_FOR_OBJC_SYMBOLS = BuiltinMacros.declareBooleanMacro("DOCC_EXTRACT_SWIFT_INFO_FOR_OBJC_SYMBOLS")
@@ -1651,6 +1652,7 @@ public final class BuiltinMacros {
16511652
DOCC_ARCHIVE_PATH,
16521653
DOCC_PRETTY_PRINT,
16531654
DOCC_SKIP_SYNTHESIZED_MEMBERS,
1655+
DOCC_MINIMUM_ACCESS_LEVEL,
16541656
DOCC_EXTRACT_SPI_DOCUMENTATION,
16551657
DOCC_EXTRACT_EXTENSION_SYMBOLS,
16561658
DOCC_EXTRACT_SWIFT_INFO_FOR_OBJC_SYMBOLS,
@@ -2759,6 +2761,18 @@ public enum LinkerDriverChoice: String, Equatable, Hashable, EnumerationMacroTyp
27592761
case auto
27602762
}
27612763

2764+
public enum DoccMinimumAccessLevel: String, Equatable, Hashable, EnumerationMacroType {
2765+
public static let defaultValue = DoccMinimumAccessLevel.none
2766+
2767+
case none = ""
2768+
case `private` = "private"
2769+
case `fileprivate` = "fileprivate"
2770+
case `internal` = "internal"
2771+
case `package` = "package"
2772+
case `public` = "public"
2773+
case `open` = "open"
2774+
}
2775+
27622776
/// Enumeration macro type for the value of the `INFOPLIST_KEY_LSApplicationCategoryType` build setting.
27632777
public enum ApplicationCategory: String, Equatable, Hashable, EnumerationMacroType {
27642778
public static let defaultValue = ApplicationCategory.none

Sources/SWBCore/SpecImplementations/PropertyDomainSpec.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ private final class EnumBuildOptionType : BuildOptionType {
118118
return try namespace.declareEnumMacro(name) as EnumMacroDeclaration<SwiftAPIDigesterMode>
119119
case "LINKER_FILE_LIST_FORMAT":
120120
return try namespace.declareEnumMacro(name) as EnumMacroDeclaration<LinkerFileListFormat>
121+
case "DOCC_MINIMUM_ACCESS_LEVEL":
122+
return try namespace.declareEnumMacro(name) as EnumMacroDeclaration<DoccMinimumAccessLevel>
121123
default:
122124
return try namespace.declareStringMacro(name)
123125
}

Sources/SWBCore/SpecImplementations/Tools/DocumentationCompiler.swift

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ final public class DocumentationCompilerSpec: GenericCompilerSpec, SpecIdentifie
7878
var additionalFlags = [String]()
7979

8080
// Check if pretty print is requested
81-
if cbc.scope.evaluate(BuiltinMacros.DOCC_PRETTY_PRINT) && swiftCompilerInfo.toolFeatures.has(.emitExtensionBlockSymbols) {
81+
if cbc.scope.evaluate(BuiltinMacros.DOCC_PRETTY_PRINT) {
8282
additionalFlags.append("-symbol-graph-pretty-print")
8383
}
8484

@@ -88,19 +88,34 @@ final public class DocumentationCompilerSpec: GenericCompilerSpec, SpecIdentifie
8888
}
8989

9090
// Check if synthesized members should be skipped
91-
if cbc.scope.evaluate(BuiltinMacros.DOCC_SKIP_SYNTHESIZED_MEMBERS) && swiftCompilerInfo.toolFeatures.has(.emitExtensionBlockSymbols) {
91+
if cbc.scope.evaluate(BuiltinMacros.DOCC_SKIP_SYNTHESIZED_MEMBERS) {
9292
additionalFlags.append("-symbol-graph-skip-synthesized-members")
9393
}
9494

95-
switch DocumentationType(from: cbc) {
96-
case .executable:
97-
// When building executable types (like applications and command-line tools), include
98-
// internal symbols in the generated symbol graph.
95+
switch cbc.scope.evaluate(BuiltinMacros.DOCC_MINIMUM_ACCESS_LEVEL) {
96+
case .none:
97+
switch DocumentationType(from: cbc) {
98+
case .executable:
99+
// When building executable types (like applications and command-line tools), include
100+
// internal symbols in the generated symbol graph.
101+
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "internal"])
102+
case .framework, .none:
103+
// For frameworks (and non-documentable types), just use the default behavior
104+
// of the symbol graph tool.
105+
return additionalFlags
106+
}
107+
case .private:
108+
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "private"])
109+
case .fileprivate:
110+
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "fileprivate"])
111+
case .internal:
99112
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "internal"])
100-
case .framework, .none:
101-
// For frameworks (and non-documentable types), just use the default behavior
102-
// of the symbol graph tool.
103-
return additionalFlags
113+
case .package:
114+
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "package"])
115+
case .public:
116+
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "public"])
117+
case .open:
118+
return additionalFlags.appending(contentsOf: ["-symbol-graph-minimum-access-level", "open"])
104119
}
105120
}
106121

Sources/SWBUniversalPlatform/Specs/Documentation.xcspec

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,22 @@
175175
DefaultValue = NO;
176176
},
177177

178+
// The minimum access level for API for the symbol graph extractor to generate
179+
{
180+
Name = DOCC_MINIMUM_ACCESS_LEVEL;
181+
Type = Enumeration;
182+
Values = (
183+
none,
184+
private,
185+
fileprivate,
186+
internal,
187+
package,
188+
public,
189+
open,
190+
);
191+
DefaultValue = none;
192+
},
193+
178194
{
179195
Name = DOCC_EXTRACT_SWIFT_INFO_FOR_OBJC_SYMBOLS;
180196
Type = bool;

Tests/SWBCoreTests/DocumentationCompilerSpecTests.swift

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,57 @@ import SWBMacro
3333
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
3434
)
3535
#expect(frameworkArgs == [])
36+
37+
let publicArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
38+
try mockApplicationBuildContext(application: false, minimumAccessLevel: .public),
39+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
40+
)
41+
#expect(publicArgs == ["-symbol-graph-minimum-access-level", "public"])
42+
43+
let privateArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
44+
try mockApplicationBuildContext(application: false, minimumAccessLevel: .private),
45+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
46+
)
47+
#expect(privateArgs == ["-symbol-graph-minimum-access-level", "private"])
48+
49+
let filePrivateArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
50+
try mockApplicationBuildContext(application: false, minimumAccessLevel: .fileprivate),
51+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
52+
)
53+
#expect(filePrivateArgs == ["-symbol-graph-minimum-access-level", "fileprivate"])
54+
55+
let internalArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
56+
try mockApplicationBuildContext(application: false, minimumAccessLevel: .internal),
57+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
58+
)
59+
#expect(internalArgs == ["-symbol-graph-minimum-access-level", "internal"])
60+
61+
let openArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
62+
try mockApplicationBuildContext(application: false, minimumAccessLevel: .open),
63+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
64+
)
65+
#expect(openArgs == ["-symbol-graph-minimum-access-level", "open"])
66+
67+
let packageArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
68+
try mockApplicationBuildContext(application: false, minimumAccessLevel: .package),
69+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
70+
)
71+
#expect(packageArgs == ["-symbol-graph-minimum-access-level", "package"])
72+
73+
let prettyPrintArgs = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
74+
try mockApplicationBuildContext(application: false, prettyPrint: true),
75+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
76+
)
77+
#expect(prettyPrintArgs == ["-symbol-graph-pretty-print"])
78+
79+
let skipSynthesizedMembers = await DocumentationCompilerSpec.additionalSymbolGraphGenerationArgs(
80+
try mockApplicationBuildContext(application: false, skipSynthesizedMembers: true),
81+
swiftCompilerInfo: try mockSwiftCompilerSpec(swiftVersion: "5.6", swiftTag: "swiftlang-5.6.0.0")
82+
)
83+
#expect(skipSynthesizedMembers == ["-symbol-graph-skip-synthesized-members"])
3684
}
3785

38-
private func mockApplicationBuildContext(application: Bool) async throws -> CommandBuildContext {
86+
private func mockApplicationBuildContext(application: Bool, minimumAccessLevel: DoccMinimumAccessLevel = .none, prettyPrint: Bool = false, skipSynthesizedMembers: Bool = false) async throws -> CommandBuildContext {
3987
let core = try await getCore()
4088

4189
let producer = try MockCommandProducer(
@@ -49,6 +97,16 @@ import SWBMacro
4997
mockTable.push(BuiltinMacros.MACH_O_TYPE, literal: "mh_execute")
5098
}
5199

100+
mockTable.push(BuiltinMacros.DOCC_MINIMUM_ACCESS_LEVEL, literal: minimumAccessLevel)
101+
102+
if prettyPrint {
103+
mockTable.push(BuiltinMacros.DOCC_PRETTY_PRINT, literal: true)
104+
}
105+
106+
if skipSynthesizedMembers {
107+
mockTable.push(BuiltinMacros.DOCC_SKIP_SYNTHESIZED_MEMBERS, literal: skipSynthesizedMembers)
108+
}
109+
52110
let mockScope = MacroEvaluationScope(table: mockTable)
53111

54112
return CommandBuildContext(producer: producer, scope: mockScope, inputs: [])

0 commit comments

Comments
 (0)