From ae9fdec3dc5316b7b9bd6812b7b8530add0f9a05 Mon Sep 17 00:00:00 2001 From: Vera Mitchell Date: Fri, 18 Jul 2025 16:00:34 -0600 Subject: [PATCH 1/2] enforce overload declaration ordering when finding LCS rdar://155975575 --- .../DeclarationsSectionTranslator.swift | 12 +- .../DeclarationsRenderSectionTests.swift | 59 +++ .../FancierOverloads.symbols.json | 404 ++++++++++++++++++ 3 files changed, 472 insertions(+), 3 deletions(-) create mode 100644 Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json diff --git a/Sources/SwiftDocC/Model/Rendering/RenderSectionTranslator/DeclarationsSectionTranslator.swift b/Sources/SwiftDocC/Model/Rendering/RenderSectionTranslator/DeclarationsSectionTranslator.swift index cc8821034..d54753bd4 100644 --- a/Sources/SwiftDocC/Model/Rendering/RenderSectionTranslator/DeclarationsSectionTranslator.swift +++ b/Sources/SwiftDocC/Model/Rendering/RenderSectionTranslator/DeclarationsSectionTranslator.swift @@ -44,13 +44,17 @@ struct DeclarationsSectionTranslator: RenderSectionTranslator { /// Fetch the common fragments for the given references, or compute it if necessary. func commonFragments( for mainDeclaration: OverloadDeclaration, - overloadDeclarations: [OverloadDeclaration] + overloadDeclarations: [OverloadDeclaration], + mainDeclarationIndex: Int ) -> [SymbolGraph.Symbol.DeclarationFragments.Fragment] { if let fragments = commonFragments(for: mainDeclaration.reference) { return fragments } - let preProcessedDeclarations = [mainDeclaration.declaration] + overloadDeclarations.map(\.declaration) + var preProcessedDeclarations = overloadDeclarations.map(\.declaration) + // Insert the main declaration according to the display index so the ordering is consistent + // between overloaded symbols + preProcessedDeclarations.insert(mainDeclaration.declaration, at: mainDeclarationIndex) // Collect the "common fragments" so we can highlight the ones that are different // in each declaration @@ -216,7 +220,9 @@ struct DeclarationsSectionTranslator: RenderSectionTranslator { // in each declaration let commonFragments = commonFragments( for: (mainDeclaration, renderNode.identifier, nil), - overloadDeclarations: processedOverloadDeclarations) + overloadDeclarations: processedOverloadDeclarations, + mainDeclarationIndex: overloads.displayIndex + ) renderedTokens = translateDeclaration( mainDeclaration, diff --git a/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift b/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift index b7a887235..cbae795da 100644 --- a/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift +++ b/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift @@ -322,6 +322,56 @@ class DeclarationsRenderSectionTests: XCTestCase { } } + func testInconsistentHighlightDiff() throws { + enableFeatureFlag(\.isExperimentalOverloadedSymbolPresentationEnabled) + + let symbolGraphFile = Bundle.module.url( + forResource: "FancierOverloads", + withExtension: "symbols.json", + subdirectory: "Test Resources" + )! + + let catalog = Folder(name: "unit-test.docc", content: [ + InfoPlist(displayName: "FancierOverloads", identifier: "com.test.example"), + CopyOfFile(original: symbolGraphFile), + ]) + + let (bundle, context) = try loadBundle(catalog: catalog) + + // The symbol graph contains two overloaded methods with modified declarations. + // The overloaded declarations have two legitimate solutions for their longest common subsequence: + // one that ends in a close-parenthesis, and one that ends in a space. + // This can create inconsistencies when run many times. + // Ensure that the overload difference highlighting is consistent for these declarations. + + // init(_ content: MyClass) throws + // init(_ content: some ConvertibleToMyClass) + + func assertDeclarations(for referencePath: String, file: StaticString = #filePath, line: UInt = #line) throws { + let reference = ResolvedTopicReference( + bundleID: bundle.id, + path: referencePath, + sourceLanguage: .swift + ) + let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Symbol, file: file, line: line) + var translator = RenderNodeTranslator(context: context, bundle: bundle, identifier: reference) + let renderNode = try XCTUnwrap(translator.visitSymbol(symbol) as? RenderNode, file: file, line: line) + let declarationsSection = try XCTUnwrap(renderNode.primaryContentSections.compactMap({ $0 as? DeclarationsRenderSection }).first, file: file, line: line) + XCTAssertEqual(declarationsSection.declarations.count, 1, file: file, line: line) + let declarations = try XCTUnwrap(declarationsSection.declarations.first, file: file, line: line) + + XCTAssertEqual(declarationsAndHighlights(for: declarations), [ + "init(_ content: MyClass) throws", + " ~~~~~~~~ ~~~~~~", + "init(_ content: some ConvertibleToMyClass)", + " ~~~~ ~~~~~~~~~~~~~~~~~~~~~", + ], file: file, line: line) + } + + try assertDeclarations(for: "/documentation/FancierOverloads/doSomething(with:)") + try assertDeclarations(for: "/documentation/FancierOverloads/doSomething(with:)-vjl7") + } + func testDontHighlightWhenOverloadsAreDisabled() throws { let symbolGraphFile = Bundle.module.url( forResource: "FancyOverloads", @@ -403,3 +453,12 @@ func declarationAndHighlights(for tokens: [DeclarationRenderSection.Token]) -> [ tokens.map({ String(repeating: $0.highlight == .changed ? "~" : " ", count: $0.text.count) }).joined() ] } + +func declarationsAndHighlights(for section: DeclarationRenderSection) -> [String] { + guard let otherDeclarations = section.otherDeclarations else { + return [] + } + var declarations = otherDeclarations.declarations.map(\.tokens) + declarations.insert(section.tokens, at: otherDeclarations.displayIndex) + return declarations.flatMap(declarationAndHighlights(for:)) +} diff --git a/Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json b/Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json new file mode 100644 index 000000000..c32dd8e6d --- /dev/null +++ b/Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json @@ -0,0 +1,404 @@ +{ + "metadata": { + "formatVersion": { + "major": 0, + "minor": 6, + "patch": 0 + }, + "generator": "Apple Swift version 6.2 (swiftlang-6.2.0.13.10 clang-1700.3.13.4)" + }, + "module": { + "name": "FancierOverloads", + "platform": { + "architecture": "arm64", + "vendor": "apple", + "operatingSystem": { + "name": "macosx", + "minimumVersion": { + "major": 12, + "minor": 4 + } + } + } + }, + "symbols": [ + { + "kind": { + "identifier": "swift.class", + "displayName": "Class" + }, + "identifier": { + "precise": "s:13FancierOverloads7MyClassC", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "MyClass" + ], + "names": { + "title": "MyClass", + "navigator": [ + { + "kind": "identifier", + "spelling": "MyClass" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyClass" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "class" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "MyClass" + } + ], + "accessLevel": "public" + }, + { + "kind": { + "identifier": "swift.protocol", + "displayName": "Protocol" + }, + "identifier": { + "precise": "s:13FancierOverloads20ConvertibleToMyClassP", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "ConvertibleToMyClass" + ], + "names": { + "title": "ConvertibleToMyClass", + "navigator": [ + { + "kind": "identifier", + "spelling": "ConvertibleToMyClass" + } + ], + "subHeading": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "ConvertibleToMyClass" + } + ] + }, + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "protocol" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "ConvertibleToMyClass" + } + ], + "accessLevel": "public" + }, + { + "kind": { + "identifier": "swift.func", + "displayName": "Function" + }, + "identifier": { + "precise": "s:13FancierOverloads11doSomething4withyAA7MyClassC_tF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "doSomething(with:)" + ], + "names": { + "title": "doSomething(with:)", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "doSomething" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "externalParam", + "spelling": "with" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "MyClass", + "preciseIdentifier": "s:13FancierOverloads7MyClassC" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "keyword", + "spelling": "throws" + } + ] + }, + "functionSignature": { + "parameters": [ + { + "name": "with", + "internalName": "object", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "object" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "typeIdentifier", + "spelling": "MyClass", + "preciseIdentifier": "s:13FancierOverloads7MyClassC" + } + ] + } + ], + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "declarationFragments": [ + { + "kind" : "keyword", + "spelling" : "init" + }, + { + "kind" : "text", + "spelling" : "(" + }, + { + "kind" : "externalParam", + "spelling" : "_" + }, + { + "kind" : "text", + "spelling" : " " + }, + { + "kind" : "internalParam", + "spelling" : "content" + }, + { + "kind" : "text", + "spelling" : ": " + }, + { + "kind" : "typeIdentifier", + "preciseIdentifier" : "s:13FancierOverloads7MyClassC", + "spelling" : "MyClass" + }, + { + "kind" : "text", + "spelling" : ") " + }, + { + "kind" : "keyword", + "spelling" : "throws" + } + + ], + "accessLevel": "public" + }, + { + "kind": { + "identifier": "swift.func", + "displayName": "Function" + }, + "identifier": { + "precise": "s:13FancierOverloads11doSomething4withyx_tAA20ConvertibleToMyClassRzlF", + "interfaceLanguage": "swift" + }, + "pathComponents": [ + "doSomething(with:)" + ], + "names": { + "title": "doSomething(with:)", + "subHeading": [ + { + "kind": "keyword", + "spelling": "func" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "identifier", + "spelling": "doSomething" + }, + { + "kind": "text", + "spelling": "(" + }, + { + "kind": "externalParam", + "spelling": "with" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "keyword", + "spelling": "some" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "ConvertibleToMyClass", + "preciseIdentifier": "s:13FancierOverloads20ConvertibleToMyClassP" + }, + { + "kind": "text", + "spelling": ")" + } + ] + }, + "functionSignature": { + "parameters": [ + { + "name": "with", + "internalName": "factory", + "declarationFragments": [ + { + "kind": "identifier", + "spelling": "factory" + }, + { + "kind": "text", + "spelling": ": " + }, + { + "kind": "keyword", + "spelling": "some" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "spelling": "ConvertibleToMyClass", + "preciseIdentifier": "s:13FancierOverloads20ConvertibleToMyClassP" + } + ] + } + ], + "returns": [ + { + "kind": "text", + "spelling": "()" + } + ] + }, + "swiftGenerics": { + "constraints": [ + { + "kind": "conformance", + "lhs": "some ConvertibleToMyClass", + "rhs": "ConvertibleToMyClass", + "rhsPrecise": "s:13FancierOverloads20ConvertibleToMyClassP" + } + ] + }, + "declarationFragments": [ + { + "kind" : "keyword", + "spelling" : "init" + }, + { + "kind" : "text", + "spelling" : "(" + }, + { + "kind" : "externalParam", + "spelling" : "_" + }, + { + "kind" : "text", + "spelling" : " " + }, + { + "kind" : "internalParam", + "spelling" : "content" + }, + { + "kind" : "text", + "spelling" : ": " + }, + { + "kind" : "keyword", + "spelling" : "some" + }, + { + "kind" : "text", + "spelling" : " " + }, + { + "kind" : "typeIdentifier", + "preciseIdentifier" : "s:13FancierOverloads20ConvertibleToMyClassP", + "spelling" : "ConvertibleToMyClass" + }, + { + "kind" : "text", + "spelling" : ")" + } + ], + "accessLevel": "public" + } + ], + "relationships": [] +} From 173a686f059134691146b1d29e456fbd3b93314a Mon Sep 17 00:00:00 2001 From: Vera Mitchell Date: Mon, 21 Jul 2025 12:01:05 -0600 Subject: [PATCH 2/2] add test that always fails without sorting the declarations --- .../DeclarationsRenderSectionTests.swift | 82 +++- .../FancierOverloads.symbols.json | 404 ------------------ 2 files changed, 59 insertions(+), 427 deletions(-) delete mode 100644 Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json diff --git a/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift b/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift index cbae795da..8208f894f 100644 --- a/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift +++ b/Tests/SwiftDocCTests/Rendering/DeclarationsRenderSectionTests.swift @@ -12,6 +12,7 @@ import Foundation import XCTest @testable import SwiftDocC import SwiftDocCTestUtilities +import SymbolKit class DeclarationsRenderSectionTests: XCTestCase { func testDecodingTokens() throws { @@ -325,34 +326,67 @@ class DeclarationsRenderSectionTests: XCTestCase { func testInconsistentHighlightDiff() throws { enableFeatureFlag(\.isExperimentalOverloadedSymbolPresentationEnabled) - let symbolGraphFile = Bundle.module.url( - forResource: "FancierOverloads", - withExtension: "symbols.json", - subdirectory: "Test Resources" - )! - - let catalog = Folder(name: "unit-test.docc", content: [ - InfoPlist(displayName: "FancierOverloads", identifier: "com.test.example"), - CopyOfFile(original: symbolGraphFile), - ]) - - let (bundle, context) = try loadBundle(catalog: catalog) - - // The symbol graph contains two overloaded methods with modified declarations. + // Generate a symbol graph with many overload groups that share declarations. // The overloaded declarations have two legitimate solutions for their longest common subsequence: // one that ends in a close-parenthesis, and one that ends in a space. - // This can create inconsistencies when run many times. + // By alternating the order in which these declarations appear, + // the computed difference highlighting can differ + // unless the declarations are sorted prior to the calculation. // Ensure that the overload difference highlighting is consistent for these declarations. // init(_ content: MyClass) throws + let declaration1: SymbolGraph.Symbol.DeclarationFragments = .init(declarationFragments: [ + .init(kind: .keyword, spelling: "init", preciseIdentifier: nil), + .init(kind: .text, spelling: "(", preciseIdentifier: nil), + .init(kind: .externalParameter, spelling: "_", preciseIdentifier: nil), + .init(kind: .text, spelling: " ", preciseIdentifier: nil), + .init(kind: .internalParameter, spelling: "content", preciseIdentifier: nil), + .init(kind: .text, spelling: ": ", preciseIdentifier: nil), + .init(kind: .typeIdentifier, spelling: "MyClass", preciseIdentifier: "s:MyClass"), + .init(kind: .text, spelling: ") ", preciseIdentifier: nil), + .init(kind: .keyword, spelling: "throws", preciseIdentifier: nil), + ]) + // init(_ content: some ConvertibleToMyClass) + let declaration2: SymbolGraph.Symbol.DeclarationFragments = .init(declarationFragments: [ + .init(kind: .keyword, spelling: "init", preciseIdentifier: nil), + .init(kind: .text, spelling: "(", preciseIdentifier: nil), + .init(kind: .externalParameter, spelling: "_", preciseIdentifier: nil), + .init(kind: .text, spelling: " ", preciseIdentifier: nil), + .init(kind: .internalParameter, spelling: "content", preciseIdentifier: nil), + .init(kind: .text, spelling: ": ", preciseIdentifier: nil), + .init(kind: .keyword, spelling: "some", preciseIdentifier: nil), + .init(kind: .text, spelling: " ", preciseIdentifier: nil), + .init(kind: .typeIdentifier, spelling: "ConvertibleToMyClass", preciseIdentifier: "s:ConvertibleToMyClass"), + .init(kind: .text, spelling: ")", preciseIdentifier: nil), + ]) + let overloadsCount = 10 + let symbols = (0...overloadsCount).flatMap({ index in + let reverseDeclarations = index % 2 != 0 + return [ + makeSymbol( + id: "overload-\(index)-1", + kind: .func, + pathComponents: ["overload-\(index)"], + otherMixins: [reverseDeclarations ? declaration2 : declaration1]), + makeSymbol( + id: "overload-\(index)-2", + kind: .func, + pathComponents: ["overload-\(index)"], + otherMixins: [reverseDeclarations ? declaration1 : declaration2]), + ] + }) + let symbolGraph = makeSymbolGraph(moduleName: "FancierOverloads", symbols: symbols) - func assertDeclarations(for referencePath: String, file: StaticString = #filePath, line: UInt = #line) throws { - let reference = ResolvedTopicReference( - bundleID: bundle.id, - path: referencePath, - sourceLanguage: .swift - ) + let catalog = Folder(name: "unit-test.docc", content: [ + InfoPlist(displayName: "FancierOverloads", identifier: "com.test.example"), + JSONFile(name: "FancierOverloads.symbols.json", content: symbolGraph), + ]) + + let (bundle, context) = try loadBundle(catalog: catalog) + + func assertDeclarations(for USR: String, file: StaticString = #filePath, line: UInt = #line) throws { + let reference = try XCTUnwrap(context.documentationCache.reference(symbolID: USR), file: file, line: line) let symbol = try XCTUnwrap(context.entity(with: reference).semantic as? Symbol, file: file, line: line) var translator = RenderNodeTranslator(context: context, bundle: bundle, identifier: reference) let renderNode = try XCTUnwrap(translator.visitSymbol(symbol) as? RenderNode, file: file, line: line) @@ -368,8 +402,10 @@ class DeclarationsRenderSectionTests: XCTestCase { ], file: file, line: line) } - try assertDeclarations(for: "/documentation/FancierOverloads/doSomething(with:)") - try assertDeclarations(for: "/documentation/FancierOverloads/doSomething(with:)-vjl7") + for i in 0...overloadsCount { + try assertDeclarations(for: "overload-\(i)-1") + try assertDeclarations(for: "overload-\(i)-2") + } } func testDontHighlightWhenOverloadsAreDisabled() throws { diff --git a/Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json b/Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json deleted file mode 100644 index c32dd8e6d..000000000 --- a/Tests/SwiftDocCTests/Test Resources/FancierOverloads.symbols.json +++ /dev/null @@ -1,404 +0,0 @@ -{ - "metadata": { - "formatVersion": { - "major": 0, - "minor": 6, - "patch": 0 - }, - "generator": "Apple Swift version 6.2 (swiftlang-6.2.0.13.10 clang-1700.3.13.4)" - }, - "module": { - "name": "FancierOverloads", - "platform": { - "architecture": "arm64", - "vendor": "apple", - "operatingSystem": { - "name": "macosx", - "minimumVersion": { - "major": 12, - "minor": 4 - } - } - } - }, - "symbols": [ - { - "kind": { - "identifier": "swift.class", - "displayName": "Class" - }, - "identifier": { - "precise": "s:13FancierOverloads7MyClassC", - "interfaceLanguage": "swift" - }, - "pathComponents": [ - "MyClass" - ], - "names": { - "title": "MyClass", - "navigator": [ - { - "kind": "identifier", - "spelling": "MyClass" - } - ], - "subHeading": [ - { - "kind": "keyword", - "spelling": "class" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "MyClass" - } - ] - }, - "declarationFragments": [ - { - "kind": "keyword", - "spelling": "class" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "MyClass" - } - ], - "accessLevel": "public" - }, - { - "kind": { - "identifier": "swift.protocol", - "displayName": "Protocol" - }, - "identifier": { - "precise": "s:13FancierOverloads20ConvertibleToMyClassP", - "interfaceLanguage": "swift" - }, - "pathComponents": [ - "ConvertibleToMyClass" - ], - "names": { - "title": "ConvertibleToMyClass", - "navigator": [ - { - "kind": "identifier", - "spelling": "ConvertibleToMyClass" - } - ], - "subHeading": [ - { - "kind": "keyword", - "spelling": "protocol" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "ConvertibleToMyClass" - } - ] - }, - "declarationFragments": [ - { - "kind": "keyword", - "spelling": "protocol" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "ConvertibleToMyClass" - } - ], - "accessLevel": "public" - }, - { - "kind": { - "identifier": "swift.func", - "displayName": "Function" - }, - "identifier": { - "precise": "s:13FancierOverloads11doSomething4withyAA7MyClassC_tF", - "interfaceLanguage": "swift" - }, - "pathComponents": [ - "doSomething(with:)" - ], - "names": { - "title": "doSomething(with:)", - "subHeading": [ - { - "kind": "keyword", - "spelling": "func" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "doSomething" - }, - { - "kind": "text", - "spelling": "(" - }, - { - "kind": "externalParam", - "spelling": "with" - }, - { - "kind": "text", - "spelling": ": " - }, - { - "kind": "typeIdentifier", - "spelling": "MyClass", - "preciseIdentifier": "s:13FancierOverloads7MyClassC" - }, - { - "kind": "text", - "spelling": ") " - }, - { - "kind": "keyword", - "spelling": "throws" - } - ] - }, - "functionSignature": { - "parameters": [ - { - "name": "with", - "internalName": "object", - "declarationFragments": [ - { - "kind": "identifier", - "spelling": "object" - }, - { - "kind": "text", - "spelling": ": " - }, - { - "kind": "typeIdentifier", - "spelling": "MyClass", - "preciseIdentifier": "s:13FancierOverloads7MyClassC" - } - ] - } - ], - "returns": [ - { - "kind": "text", - "spelling": "()" - } - ] - }, - "declarationFragments": [ - { - "kind" : "keyword", - "spelling" : "init" - }, - { - "kind" : "text", - "spelling" : "(" - }, - { - "kind" : "externalParam", - "spelling" : "_" - }, - { - "kind" : "text", - "spelling" : " " - }, - { - "kind" : "internalParam", - "spelling" : "content" - }, - { - "kind" : "text", - "spelling" : ": " - }, - { - "kind" : "typeIdentifier", - "preciseIdentifier" : "s:13FancierOverloads7MyClassC", - "spelling" : "MyClass" - }, - { - "kind" : "text", - "spelling" : ") " - }, - { - "kind" : "keyword", - "spelling" : "throws" - } - - ], - "accessLevel": "public" - }, - { - "kind": { - "identifier": "swift.func", - "displayName": "Function" - }, - "identifier": { - "precise": "s:13FancierOverloads11doSomething4withyx_tAA20ConvertibleToMyClassRzlF", - "interfaceLanguage": "swift" - }, - "pathComponents": [ - "doSomething(with:)" - ], - "names": { - "title": "doSomething(with:)", - "subHeading": [ - { - "kind": "keyword", - "spelling": "func" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "identifier", - "spelling": "doSomething" - }, - { - "kind": "text", - "spelling": "(" - }, - { - "kind": "externalParam", - "spelling": "with" - }, - { - "kind": "text", - "spelling": ": " - }, - { - "kind": "keyword", - "spelling": "some" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "typeIdentifier", - "spelling": "ConvertibleToMyClass", - "preciseIdentifier": "s:13FancierOverloads20ConvertibleToMyClassP" - }, - { - "kind": "text", - "spelling": ")" - } - ] - }, - "functionSignature": { - "parameters": [ - { - "name": "with", - "internalName": "factory", - "declarationFragments": [ - { - "kind": "identifier", - "spelling": "factory" - }, - { - "kind": "text", - "spelling": ": " - }, - { - "kind": "keyword", - "spelling": "some" - }, - { - "kind": "text", - "spelling": " " - }, - { - "kind": "typeIdentifier", - "spelling": "ConvertibleToMyClass", - "preciseIdentifier": "s:13FancierOverloads20ConvertibleToMyClassP" - } - ] - } - ], - "returns": [ - { - "kind": "text", - "spelling": "()" - } - ] - }, - "swiftGenerics": { - "constraints": [ - { - "kind": "conformance", - "lhs": "some ConvertibleToMyClass", - "rhs": "ConvertibleToMyClass", - "rhsPrecise": "s:13FancierOverloads20ConvertibleToMyClassP" - } - ] - }, - "declarationFragments": [ - { - "kind" : "keyword", - "spelling" : "init" - }, - { - "kind" : "text", - "spelling" : "(" - }, - { - "kind" : "externalParam", - "spelling" : "_" - }, - { - "kind" : "text", - "spelling" : " " - }, - { - "kind" : "internalParam", - "spelling" : "content" - }, - { - "kind" : "text", - "spelling" : ": " - }, - { - "kind" : "keyword", - "spelling" : "some" - }, - { - "kind" : "text", - "spelling" : " " - }, - { - "kind" : "typeIdentifier", - "preciseIdentifier" : "s:13FancierOverloads20ConvertibleToMyClassP", - "spelling" : "ConvertibleToMyClass" - }, - { - "kind" : "text", - "spelling" : ")" - } - ], - "accessLevel": "public" - } - ], - "relationships": [] -}