diff --git a/Package.resolved b/Package.resolved index ffb8d1e20..ca13d9b29 100644 --- a/Package.resolved +++ b/Package.resolved @@ -69,7 +69,7 @@ "location" : "https://github.com/swiftlang/swift-docc-symbolkit.git", "state" : { "branch" : "main", - "revision" : "96bce1cfad4f4d7e265c1eb46729ebf8a7695f4b" + "revision" : "65fa99b0b84db5c743415a00ee7f0099837aae1b" } }, { diff --git a/Sources/SwiftDocC/Model/Rendering/Symbol/ConformanceSection.swift b/Sources/SwiftDocC/Model/Rendering/Symbol/ConformanceSection.swift index 7048c13d3..73ca49b21 100644 --- a/Sources/SwiftDocC/Model/Rendering/Symbol/ConformanceSection.swift +++ b/Sources/SwiftDocC/Model/Rendering/Symbol/ConformanceSection.swift @@ -20,6 +20,7 @@ extension Constraint.Kind { case .conformance: return "conforms to" case .sameType: return "is" case .superclass: return "inherits" + case .sameShape: return "is the same shape as" } } } diff --git a/Tests/SwiftDocCTests/Rendering/ConstraintsRenderSectionTests.swift b/Tests/SwiftDocCTests/Rendering/ConstraintsRenderSectionTests.swift index 7b67c5499..19bd1673a 100644 --- a/Tests/SwiftDocCTests/Rendering/ConstraintsRenderSectionTests.swift +++ b/Tests/SwiftDocCTests/Rendering/ConstraintsRenderSectionTests.swift @@ -11,6 +11,7 @@ import Foundation import XCTest @testable import SwiftDocC +import SwiftDocCTestUtilities import SymbolKit fileprivate let jsonDecoder = JSONDecoder() @@ -273,6 +274,39 @@ class ConstraintsRenderSectionTests: XCTestCase { // Verify we've removed the "Self." prefix in the type names XCTAssertEqual(renderReference.conformance?.constraints.map(flattenInlineElements).joined(), "Element conforms to MyProtocol and Index conforms to Equatable.") } + + func testRenderSameShape() async throws { + let symbolGraphFile = Bundle.module.url( + forResource: "SameShapeConstraint", + withExtension: "symbols.json", + subdirectory: "Test Resources" + )! + + let catalog = Folder(name: "unit-test.docc", content: [ + InfoPlist(displayName: "SameShapeConstraint", identifier: "com.test.example"), + CopyOfFile(original: symbolGraphFile), + ]) + + let (_, context) = try await loadBundle(catalog: catalog) + + // Compile docs and verify contents + let node = try context.entity(with: ResolvedTopicReference(bundleID: context.inputs.id, path: "/documentation/SameShapeConstraint/function(_:)", sourceLanguage: .swift)) + let symbol = node.semantic as! Symbol + var translator = RenderNodeTranslator(context: context, identifier: node.reference) + let renderNode = translator.visitSymbol(symbol) as! RenderNode + + guard let renderReference = renderNode.references.first(where: { (key, value) -> Bool in + return key.hasSuffix("function(_:)") + })?.value as? TopicRenderReference else { + XCTFail("Did not find render reference to function(_:)") + return + } + + // The symbol graph only defines constraints on the `swiftGenerics` mixin, + // which docc doesn't load or render. + // However, this test should still run without crashing on decoding the symbol graph. + XCTAssertEqual(renderReference.conformance?.constraints.map(flattenInlineElements).joined(), nil) + } } fileprivate func flattenInlineElements(el: RenderInlineContent) -> String { diff --git a/Tests/SwiftDocCTests/Test Resources/SameShapeConstraint.symbols.json b/Tests/SwiftDocCTests/Test Resources/SameShapeConstraint.symbols.json new file mode 100644 index 000000000..183b29cd2 --- /dev/null +++ b/Tests/SwiftDocCTests/Test Resources/SameShapeConstraint.symbols.json @@ -0,0 +1,321 @@ +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 6, + "patch": 0 + }, + "generator": "Apple Swift version 6.2 (swiftlang-6.2.0.19.9 clang-1700.3.19.1)" + }, + "module": { + "name": "SameShapeConstraint", + "platform": { + "architecture": "arm64", + "vendor": "apple", + "operatingSystem": { + "name": "macosx", + "minimumVersion": { + "major": 12, + "minor": 4 + } + } + } + }, + "symbols": [ + { + "kind": { + "identifier": "swift.func", + "displayName": "Function" + }, + "identifier": { + "precise": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "function(_:)" + ], + "names": { + "title": "function(_:)", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "function" + }, + { + "kind": "text", + "spelling": "((" + }, + { + "kind": "keyword", + "spelling": "repeat" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "each" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Element0", + "preciseIdentifier": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF8Element0L_xmfp" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "keyword", + "spelling": "each" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Element1", + "preciseIdentifier": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF8Element1L_q_mfp" + }, + { + "kind": "text", + "spelling": ")))" + } + ] + }, + "functionSignature": { + "parameters": [ + { + "name": "_", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "_" + }, + { + "kind": "text", + "spelling": ": (" + }, + { + "kind": "keyword", + "spelling": "repeat" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "each" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Element0", + "preciseIdentifier": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF8Element0L_xmfp" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "keyword", + "spelling": "each" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Element1", + "preciseIdentifier": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF8Element1L_q_mfp" + }, + { + "kind": "text", + "spelling": "))" + } + ] + } + ], + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "swiftGenerics": { + "parameters": [ + { + "name": "Element0", + "index": 0, + "depth": 0 + }, + { + "name": "Element1", + "index": 1, + "depth": 0 + } + ], + "constraints": [ + { + "kind": "sameShape", + "lhs": "each Element0", + "rhs": "each Element1" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "function" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "externalParam", + "spelling": "_" + }, + { + "kind": "text", + "spelling": ": (" + }, + { + "kind": "keyword", + "spelling": "repeat" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "keyword", + "spelling": "each" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Element0", + "preciseIdentifier": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF8Element0L_xmfp" + }, + { + "kind": "text", + "spelling": ", " + }, + { + "kind": "keyword", + "spelling": "each" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "Element1", + "preciseIdentifier": "s:13SameShapeConstraint8functionyyx_q_txQp_t_tRvzRv_q_Rhzr0_lF8Element1L_q_mfp" + }, + { + "kind": "text", + "spelling": "))) " + }, + { + "kind": "keyword", + "spelling": "where" + }, + { + "kind": "text", + "spelling": " (repeat (each " + }, + { + "kind": "typeIdentifier", + "spelling": "Element0" + }, + { + "kind": "text", + "spelling": ", each " + }, + { + "kind": "typeIdentifier", + "spelling": "Element1" + }, + { + "kind": "text", + "spelling": ")) : Any" + } + ], + "accessLevel": "public", + "location": { + "uri": "file:///path/to/SameShapeConstraint/SwiftClass.swift", + "position": { + "line": 9, + "character": 12 + } + } + } + ], + "relationships": [] +}