Skip to content

Commit 2dc63aa

Browse files
don't use obsolete/deprecated/unavailable symbols as the main symbol (#91)
rdar://138648876
1 parent 96bce1c commit 2dc63aa

File tree

2 files changed

+138
-2
lines changed

2 files changed

+138
-2
lines changed

Sources/SymbolKit/SymbolGraph/SymbolGraph.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ public struct SymbolGraph: Codable {
6161
}
6262

6363
public static func _symbolToKeepInCaseOfPreciseIdentifierConflict(_ lhs: Symbol, _ rhs: Symbol) -> Symbol {
64-
if lhs.declarationContainsAsyncKeyword() {
64+
if lhs.declarationContainsAsyncKeyword() || lhs.isObsoleteDeprecatedOrUnavailable() {
6565
var result = rhs
6666
result.addAlternateDeclaration(from: lhs)
6767
return result
68-
} else if rhs.declarationContainsAsyncKeyword() {
68+
} else if rhs.declarationContainsAsyncKeyword() || rhs.isObsoleteDeprecatedOrUnavailable() {
6969
var result = lhs
7070
result.addAlternateDeclaration(from: rhs)
7171
return result
@@ -103,4 +103,13 @@ extension SymbolGraph.Symbol {
103103
fragment.kind == .keyword && fragment.spelling == "async"
104104
}) == true
105105
}
106+
107+
fileprivate func isObsoleteDeprecatedOrUnavailable() -> Bool {
108+
return availability?.contains { availabilityItem in
109+
availabilityItem.obsoletedVersion != nil
110+
|| availabilityItem.deprecatedVersion != nil
111+
|| availabilityItem.isUnconditionallyDeprecated
112+
|| availabilityItem.isUnconditionallyUnavailable
113+
} == true
114+
}
106115
}

Tests/SymbolKitTests/SymbolGraph/SymbolGraphTests.swift

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ class SymbolGraphTests: XCTestCase {
123123
fragment.kind == .externalParameter && fragment.spelling == "completionHandler"
124124
}))
125125
}
126+
127+
func testDecodeObsoleteAlternateSymbol() throws {
128+
let jsonData = obsoleteAlternateSymbolGraph.data(using: .utf8)!
129+
let symbolGraph = try JSONDecoder().decode(SymbolGraph.self, from: jsonData)
130+
131+
XCTAssertEqual(symbolGraph.symbols.count, 1, "Only one of the symbols should be decoded")
132+
let symbol = try XCTUnwrap(symbolGraph.symbols.values.first)
133+
134+
XCTAssertEqual(symbol.names.title, "init(name:)")
135+
XCTAssertEqual(symbol.declarationFragments, [
136+
.init(kind: .identifier, spelling: "init(name:)", preciseIdentifier: nil)
137+
])
138+
139+
// The obsolete declaration should have been saved as an alternate symbol
140+
let alternateSymbols = try XCTUnwrap(symbol.alternateSymbols)
141+
let alternateDeclarations = try XCTUnwrap(alternateSymbols.alternateSymbols.compactMap(\.declarationFragments))
142+
XCTAssertEqual(alternateDeclarations.count, 1)
143+
let alternate = alternateDeclarations[0]
144+
XCTAssertEqual(alternate.declarationFragments, [
145+
.init(kind: .identifier, spelling: "init(symbolWithName:)", preciseIdentifier: nil)
146+
])
147+
}
126148
}
127149

128150
// MARK: Test Data
@@ -480,3 +502,108 @@ private func encodedLegacySymbolGraph() -> String {
480502
}
481503
"""
482504
}
505+
506+
private let obsoleteSymbolOverload: String = """
507+
{
508+
"kind": {
509+
"identifier": "swift.init",
510+
"displayName": "Initializer"
511+
},
512+
"identifier": {
513+
"precise": "c:MySymbol:symbolWithName:",
514+
"interfaceLanguage": "swift"
515+
},
516+
"pathComponents": [
517+
"MyClass",
518+
"init(symbolWithName:)"
519+
],
520+
"names": {
521+
"title": "init(symbolWithName:)",
522+
},
523+
"declarationFragments" : [
524+
{
525+
"kind" : "identifier",
526+
"spelling" : "init(symbolWithName:)"
527+
}
528+
],
529+
"accessLevel": "public",
530+
"availability": [
531+
{
532+
"domain": "Swift",
533+
"obsoleted": {
534+
"major": 3
535+
},
536+
"renamed": "init(name:)"
537+
},
538+
{
539+
"domain": "iOS",
540+
"introduced": {
541+
"major": 11,
542+
"minor": 0
543+
}
544+
}
545+
]
546+
}
547+
"""
548+
549+
private let targetSymbolOverload: String = """
550+
{
551+
"kind": {
552+
"identifier": "swift.init",
553+
"displayName": "Initializer"
554+
},
555+
"identifier": {
556+
"precise": "c:MySymbol:symbolWithName:",
557+
"interfaceLanguage": "swift"
558+
},
559+
"pathComponents": [
560+
"MySymbol",
561+
"init(name:)"
562+
],
563+
"names": {
564+
"title": "init(name:)",
565+
},
566+
"declarationFragments" : [
567+
{
568+
"kind" : "identifier",
569+
"spelling" : "init(name:)"
570+
}
571+
],
572+
"accessLevel": "public",
573+
"availability": [
574+
{
575+
"domain": "iOS",
576+
"introduced": {
577+
"major": 11,
578+
"minor": 0
579+
}
580+
}
581+
]
582+
}
583+
"""
584+
585+
private let obsoleteAlternateSymbolGraph: String = """
586+
{
587+
"metadata" : {
588+
"generator" : "unit-test",
589+
"formatVersion" : {
590+
"major" : 1,
591+
"minor" : 0,
592+
"patch" : 0
593+
}
594+
},
595+
"relationships" : [
596+
597+
],
598+
"symbols" : [
599+
\(obsoleteSymbolOverload),
600+
\(targetSymbolOverload)
601+
],
602+
"module" : {
603+
"name" : "ModuleName",
604+
"platform" : {
605+
606+
}
607+
}
608+
}
609+
"""

0 commit comments

Comments
 (0)