Skip to content

Commit 361a9f8

Browse files
sort platform-specific declarations by their platforms (#1254)
rdar://155966155
1 parent 8cba153 commit 361a9f8

File tree

2 files changed

+92
-6
lines changed

2 files changed

+92
-6
lines changed

Sources/SwiftDocC/Model/Rendering/RenderSectionTranslator/DeclarationsSectionTranslator.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,15 @@ struct DeclarationsSectionTranslator: RenderSectionTranslator {
187187
return declarations
188188
}
189189

190-
func sortPlatformNames(_ platforms: [PlatformName?]) -> [PlatformName?] {
191-
platforms.sorted { (lhs, rhs) -> Bool in
192-
guard let lhsValue = lhs, let rhsValue = rhs else {
193-
return lhs == nil
194-
}
195-
return lhsValue.rawValue < rhsValue.rawValue
190+
func comparePlatformNames(_ lhs: PlatformName?, _ rhs: PlatformName?) -> Bool {
191+
guard let lhsValue = lhs, let rhsValue = rhs else {
192+
return lhs == nil
196193
}
194+
return lhsValue.rawValue < rhsValue.rawValue
195+
}
196+
197+
func sortPlatformNames(_ platforms: [PlatformName?]) -> [PlatformName?] {
198+
platforms.sorted(by: comparePlatformNames(_:_:))
197199
}
198200

199201
var declarations: [DeclarationRenderSection] = []
@@ -265,6 +267,15 @@ struct DeclarationsSectionTranslator: RenderSectionTranslator {
265267
}
266268
}
267269

270+
declarations.sort { (lhs, rhs) -> Bool in
271+
// We only need to compare the first platform in each list against the
272+
// first platform in any other list, so pull them out here
273+
guard let lhsPlatform = lhs.platforms.first, let rhsPlatform = rhs.platforms.first else {
274+
return lhs.platforms.isEmpty
275+
}
276+
return comparePlatformNames(lhsPlatform, rhsPlatform)
277+
}
278+
268279
return DeclarationsRenderSection(declarations: declarations)
269280
}
270281
}

Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,81 @@ class DeclarationsRenderSectionTests: XCTestCase {
160160
XCTAssert(declarationsSection.declarations.allSatisfy({ $0.platforms == [.iOS, .macOS] }))
161161
}
162162

163+
func testPlatformSpecificDeclarations() throws {
164+
// init(_ content: MyClass) throws
165+
let declaration1: SymbolGraph.Symbol.DeclarationFragments = .init(declarationFragments: [
166+
.init(kind: .keyword, spelling: "init", preciseIdentifier: nil),
167+
.init(kind: .text, spelling: "(", preciseIdentifier: nil),
168+
.init(kind: .externalParameter, spelling: "_", preciseIdentifier: nil),
169+
.init(kind: .text, spelling: " ", preciseIdentifier: nil),
170+
.init(kind: .internalParameter, spelling: "content", preciseIdentifier: nil),
171+
.init(kind: .text, spelling: ": ", preciseIdentifier: nil),
172+
.init(kind: .typeIdentifier, spelling: "MyClass", preciseIdentifier: "s:MyClass"),
173+
.init(kind: .text, spelling: ") ", preciseIdentifier: nil),
174+
.init(kind: .keyword, spelling: "throws", preciseIdentifier: nil),
175+
])
176+
177+
// init(_ content: OtherClass) throws
178+
let declaration2: SymbolGraph.Symbol.DeclarationFragments = .init(declarationFragments: [
179+
.init(kind: .keyword, spelling: "init", preciseIdentifier: nil),
180+
.init(kind: .text, spelling: "(", preciseIdentifier: nil),
181+
.init(kind: .externalParameter, spelling: "_", preciseIdentifier: nil),
182+
.init(kind: .text, spelling: " ", preciseIdentifier: nil),
183+
.init(kind: .internalParameter, spelling: "content", preciseIdentifier: nil),
184+
.init(kind: .text, spelling: ": ", preciseIdentifier: nil),
185+
.init(kind: .typeIdentifier, spelling: "OtherClass", preciseIdentifier: "s:OtherClass"),
186+
.init(kind: .text, spelling: ") ", preciseIdentifier: nil),
187+
.init(kind: .keyword, spelling: "throws", preciseIdentifier: nil),
188+
])
189+
let symbol1 = makeSymbol(
190+
id: "myInit",
191+
kind: .func,
192+
pathComponents: ["myInit"],
193+
otherMixins: [declaration1])
194+
let symbol2 = makeSymbol(
195+
id: "myInit",
196+
kind: .func,
197+
pathComponents: ["myInit"],
198+
otherMixins: [declaration2])
199+
let symbolGraph1 = makeSymbolGraph(moduleName: "PlatformSpecificDeclarations", platform: .init(operatingSystem: .init(name: "macos")), symbols: [symbol1])
200+
let symbolGraph2 = makeSymbolGraph(moduleName: "PlatformSpecificDeclarations", platform: .init(operatingSystem: .init(name: "ios")), symbols: [symbol2])
201+
202+
func runAssertions(forwards: Bool) throws {
203+
// Toggling the order of platforms here doesn't necessarily _enforce_ a
204+
// nondeterminism failure in a unit-test environment, but it does make it
205+
// much more likely. Make sure that the order of the platform-specific
206+
// declarations is consistent between runs.
207+
let catalog = Folder(name: "unit-test.docc", content: [
208+
InfoPlist(displayName: "PlatformSpecificDeclarations", identifier: "com.test.example"),
209+
JSONFile(name: "symbols\(forwards ? "1" : "2").symbols.json", content: symbolGraph1),
210+
JSONFile(name: "symbols\(forwards ? "2" : "1").symbols.json", content: symbolGraph2),
211+
])
212+
213+
let (bundle, context) = try loadBundle(catalog: catalog)
214+
215+
let reference = ResolvedTopicReference(
216+
bundleID: bundle.id,
217+
path: "/documentation/PlatformSpecificDeclarations/myInit",
218+
sourceLanguage: .swift
219+
)
220+
let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Symbol)
221+
var translator = RenderNodeTranslator(context: context, bundle: bundle, identifier: reference)
222+
let renderNode = try XCTUnwrap(translator.visitSymbol(symbol) as? RenderNode)
223+
let declarationsSection = try XCTUnwrap(renderNode.primaryContentSections.compactMap({ $0 as? DeclarationsRenderSection }).first)
224+
XCTAssertEqual(declarationsSection.declarations.count, 2)
225+
226+
XCTAssertEqual(declarationsSection.declarations[0].platforms, [.iOS])
227+
XCTAssertEqual(declarationsSection.declarations[0].tokens.map(\.text).joined(),
228+
"init(_ content: OtherClass) throws")
229+
XCTAssertEqual(declarationsSection.declarations[1].platforms, [.macOS])
230+
XCTAssertEqual(declarationsSection.declarations[1].tokens.map(\.text).joined(),
231+
"init(_ content: MyClass) throws")
232+
}
233+
234+
try runAssertions(forwards: true)
235+
try runAssertions(forwards: false)
236+
}
237+
163238
func testHighlightDiff() throws {
164239
enableFeatureFlag(\.isExperimentalOverloadedSymbolPresentationEnabled)
165240

0 commit comments

Comments
 (0)