Skip to content

Commit 8e0c017

Browse files
Add availability information when the symbol does not has its own availability (#1068)
Add availability information when the symbol does not has its own availability. For ObjC symbols with no explicit availability, some custom logic was not allowing adding the missing introduced versions, causing problems like adding the platform name on a symbol when its not availabile in that platform, and removing fallback platforms. rdar://137708623
1 parent 1d9681b commit 8e0c017

File tree

2 files changed

+144
-20
lines changed

2 files changed

+144
-20
lines changed

Sources/SwiftDocC/Infrastructure/Symbol Graph/SymbolGraphLoader.swift

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -300,27 +300,21 @@ struct SymbolGraphLoader {
300300
// The availability item for each symbol of the given module.
301301
let modulePlatformAvailabilityItem = AvailabilityItem(domain: SymbolGraph.Symbol.Availability.Domain(rawValue: platformName.rawValue), introducedVersion: defaultModuleVersion, deprecatedVersion: nil, obsoletedVersion: nil, message: nil, renamed: nil, isUnconditionallyDeprecated: false, isUnconditionallyUnavailable: false, willEventuallyBeDeprecated: false)
302302
// Check if the symbol has existing availabilities from source
303-
if var availability = symbol.mixins[SymbolGraph.Symbol.Availability.mixinKey] as? SymbolGraph.Symbol.Availability {
304-
305-
// Fill introduced versions when missing.
306-
availability.availability = availability.availability.map {
307-
$0.fillingMissingIntroducedVersion(
308-
from: defaultAvailabilityVersionByPlatform,
309-
fallbackPlatform: DefaultAvailability.fallbackPlatforms[platformName]?.rawValue
310-
)
311-
}
312-
// Add the module availability information to each of the symbols availability mixin.
313-
if !availability.contains(platformName) {
314-
availability.availability.append(modulePlatformAvailabilityItem)
315-
}
316-
symbol.mixins[SymbolGraph.Symbol.Availability.mixinKey] = availability
317-
} else {
318-
// ObjC doesn't propagate symbol availability to their children properties,
319-
// so only add the default availability to the Swift variant of the symbols.
320-
if !(selector?.interfaceLanguage == InterfaceLanguage.objc.name.lowercased()) {
321-
symbol.mixins[SymbolGraph.Symbol.Availability.mixinKey] = SymbolGraph.Symbol.Availability(availability: [modulePlatformAvailabilityItem])
322-
}
303+
var availability = symbol.mixins[SymbolGraph.Symbol.Availability.mixinKey] as? SymbolGraph.Symbol.Availability ?? SymbolGraph.Symbol.Availability(availability: [])
304+
305+
// Fill introduced versions when missing.
306+
availability.availability = availability.availability.map {
307+
$0.fillingMissingIntroducedVersion(
308+
from: defaultAvailabilityVersionByPlatform,
309+
fallbackPlatform: DefaultAvailability.fallbackPlatforms[platformName]?.rawValue
310+
)
311+
}
312+
// Add the module availability information to each of the symbols availability mixin.
313+
if !availability.contains(platformName) {
314+
availability.availability.append(modulePlatformAvailabilityItem)
323315
}
316+
symbol.mixins[SymbolGraph.Symbol.Availability.mixinKey] = availability
317+
324318
return symbol
325319
}
326320
symbolGraph.symbols = symbolsWithFilledIntroducedVersions

Tests/SwiftDocCTests/Infrastructure/SymbolGraph/SymbolGraphLoaderTests.swift

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,136 @@ class SymbolGraphLoaderTests: XCTestCase {
16521652
XCTAssertEqual(availability.first(where: { $0.domain?.rawValue == "macCatalyst" })?.introducedVersion, SymbolGraph.SemanticVersion(major: 1, minor: 0, patch: 0))
16531653
}
16541654

1655+
1656+
func testDefaultAvailabilityWhenSymbolIsNotAvailableForThatPlatform() throws {
1657+
// Symbol from SGF
1658+
let symbolTVOS = """
1659+
{
1660+
"kind": {
1661+
"displayName" : "Instance Property",
1662+
"identifier" : "swift.property"
1663+
},
1664+
"identifier": {
1665+
"precise": "c:@F@A",
1666+
"interfaceLanguage": "objective-c"
1667+
},
1668+
"pathComponents": [
1669+
"Foo"
1670+
],
1671+
"names": {
1672+
"title": "Foo",
1673+
},
1674+
"accessLevel": "public"
1675+
}
1676+
"""
1677+
let symbolIOS = """
1678+
{
1679+
"kind": {
1680+
"displayName" : "Instance Property",
1681+
"identifier" : "swift.property"
1682+
},
1683+
"identifier": {
1684+
"precise": "c:@F@A",
1685+
"interfaceLanguage": "objective-c"
1686+
},
1687+
"pathComponents": [
1688+
"Foo"
1689+
],
1690+
"names": {
1691+
"title": "Foo",
1692+
},
1693+
"accessLevel": "public"
1694+
},
1695+
{
1696+
"kind": {
1697+
"displayName" : "Instance Property",
1698+
"identifier" : "swift.property"
1699+
},
1700+
"identifier": {
1701+
"precise": "c:@F@Bar",
1702+
"interfaceLanguage" : "objective-c",
1703+
},
1704+
"pathComponents": [
1705+
"Bar"
1706+
],
1707+
"names": {
1708+
"title": "Bar",
1709+
},
1710+
"accessLevel": "public"
1711+
}
1712+
"""
1713+
let tvOSSymbolGraphString = makeSymbolGraphString(
1714+
moduleName: "MyModule",
1715+
symbols: symbolTVOS,
1716+
platform: """
1717+
"operatingSystem" : {
1718+
"minimumVersion" : {
1719+
"major" : 12,
1720+
"minor" : 0,
1721+
"patch" : 0
1722+
},
1723+
"name" : "tvos"
1724+
}
1725+
"""
1726+
)
1727+
let iOSSymbolGraphString = makeSymbolGraphString(
1728+
moduleName: "MyModule",
1729+
symbols: symbolIOS,
1730+
platform: """
1731+
"operatingSystem" : {
1732+
"minimumVersion" : {
1733+
"major" : 12,
1734+
"minor" : 0,
1735+
"patch" : 0
1736+
},
1737+
"name" : "ios"
1738+
}
1739+
"""
1740+
)
1741+
var infoPlist = """
1742+
<plist version="1.0">
1743+
<dict>
1744+
<key>CDAppleDefaultAvailability</key>
1745+
<dict>
1746+
<key>MyModule</key>
1747+
<array>
1748+
<dict>
1749+
<key>name</key>
1750+
<string>iOS</string>
1751+
</dict>
1752+
<dict>
1753+
<key>name</key>
1754+
<string>tvOS</string>
1755+
</dict>
1756+
</array>
1757+
</dict>
1758+
</dict>
1759+
</plist>
1760+
"""
1761+
// Create an empty bundle
1762+
let targetURL = try createTemporaryDirectory(named: "test.docc")
1763+
// Create symbol graph file
1764+
let tvOSymbolGraphURL = targetURL.appendingPathComponent("MyModule-tvos.symbols.json")
1765+
let iOSSymbolGraphURL = targetURL.appendingPathComponent("MyModule-ios.symbols.json")
1766+
try tvOSSymbolGraphString.write(to: tvOSymbolGraphURL, atomically: true, encoding: .utf8)
1767+
try iOSSymbolGraphString.write(to: iOSSymbolGraphURL, atomically: true, encoding: .utf8)
1768+
// Create Info.plist
1769+
let infoPlistURL = targetURL.appendingPathComponent("Info.plist")
1770+
try infoPlist.write(to: infoPlistURL, atomically: true, encoding: .utf8)
1771+
// Load the bundle & reference resolve symbol graph docs
1772+
var (_, _, context) = try loadBundle(from: targetURL)
1773+
guard let availability = (context.documentationCache["c:@F@Bar"]?.semantic as? Symbol)?.availability?.availability else {
1774+
XCTFail("Did not find availability for symbol 'c:@F@Bar'")
1775+
return
1776+
}
1777+
// Verify we dont add platforms to symbols that are not in that platform SGF. Even if the
1778+
// platform is part of the default availability.
1779+
XCTAssertEqual(availability.count, 3)
1780+
XCTAssertNotNil(availability.first(where: { $0.domain?.rawValue == "iOS" }))
1781+
XCTAssertNotNil(availability.first(where: { $0.domain?.rawValue == "macCatalyst" }))
1782+
XCTAssertNotNil(availability.first(where: { $0.domain?.rawValue == "iPadOS" }))
1783+
}
1784+
16551785
// MARK: - Helpers
16561786

16571787
private func makeSymbolGraphLoader(

0 commit comments

Comments
 (0)