Skip to content

Commit c750961

Browse files
authored
Improve heuristic for extending return value with "on failure" info (#1096) (#1132)
rdar://139465971
1 parent c23571a commit c750961

15 files changed

+489
-8
lines changed

Sources/SwiftDocC/Model/ParametersAndReturnValidator.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ struct ParametersAndReturnValidator {
364364
}
365365
}
366366

367-
if returns.contents.contains(where: { $0.format().lowercased().contains("error") }) {
368-
// If the existing returns value documentation mentions "error" at all, don't add anything
367+
if returns.possiblyDocumentsFailureBehavior() {
368+
// If the existing returns value documentation appears to describe the failure / error behavior, don't add anything
369369
return nil
370370
}
371371
if signatures[.objectiveC]?.returns == [.init(kind: .typeIdentifier, spelling: "BOOL", preciseIdentifier: "c:@T@BOOL")] {
@@ -664,6 +664,24 @@ struct ParametersAndReturnValidator {
664664

665665
// MARK: Helper extensions
666666

667+
private extension Return {
668+
/// Applies a basic heuristic to give an indication if the return value documentation possibly documents what happens when an error occurs
669+
func possiblyDocumentsFailureBehavior() -> Bool {
670+
contents.contains(where: { markup in
671+
let formatted = markup.format().lowercased()
672+
673+
// Check if the authored markup contains one of a handful of words as an indication that it possibly documents what happens when an error occurs.
674+
return returnValueDescribesErrorRegex.firstMatch(in: formatted, range: NSRange(formatted.startIndex ..< formatted.endIndex, in: formatted)) != nil
675+
})
676+
}
677+
}
678+
679+
/// A regular expression that finds the words; "error", "fail", "fails", "failure", "failures", "nil", and "null".
680+
/// These words only match at word boundaries or when surrounded by single backticks ("`").
681+
///
682+
/// This is used as a heuristic to give an indication if the return value documentation possibly documents what happens when an error occurs.
683+
private let returnValueDescribesErrorRegex = try! NSRegularExpression(pattern: "(\\b|`)(error|fail(ure)?s?|nil|null)(\\b|`)", options: .caseInsensitive)
684+
667685
private extension SymbolGraph.Symbol.FunctionSignature {
668686
mutating func merge(with signature: Self, selector: UnifiedSymbolGraph.Selector) {
669687
// An internal helper function that compares parameter names

Sources/docc/DocCDocumentation.docc/documenting-api-with-different-language-representations.md renamed to Sources/docc/DocCDocumentation.docc/Documenting API with different language representations/documenting-api-with-different-language-representations.md

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ When a symbol has different parameters or return values in different source lang
3838
```objc
3939
/// - Parameters:
4040
/// - someValue: Some description of this parameter.
41-
/// - error: On output, a pointer to an error object that describes why "doing somehting" failed, or `nil` if no error occurred.
41+
/// - error: On output, a pointer to an error object that describes why "doing something" failed, or `nil` if no error occurred.
4242
/// - Returns: `YES` if "doing something" was successful, `NO` if an error occurred.
4343
- (BOOL)doSomethingWith:(NSInteger)someValue
4444
error:(NSError **)error;
@@ -52,12 +52,73 @@ func doSomething(with someValue: Int) throws
5252

5353
Because the Swift representation of this method only has the "someValue" parameter and no return value, DocC hides the "error" parameter documentation and the return value documentation from the Swift version of this symbol's page.
5454

55+
@Row {
56+
@Column {
57+
![](params-1-swift)
58+
}
59+
@Column {
60+
![](params-1-objc)
61+
}
62+
}
5563

56-
You don't need to document the Objective-C representation's "error" parameter or Objective-C specific return value for symbols defined in Swift.
57-
DocC automatically adds a generic description for the "error" parameter and extends your return value documentation to describe the Objective-C specific return value behavior.
58-
59-
If you want to customize this documentation you can manually document the "error" parameter and return value.
64+
You don't need to document the Objective-C representation's "error" parameter or the Objective-C specific return value for methods that correspond to throwing functions in Swift.
65+
DocC automatically adds a generic description for the "error" parameter for the Objective-C version of that symbol's page.
66+
If you want to customize this documentation you can manually document the "error" parameter.
6067
Doing so won't change the Swift version of that symbol's page.
61-
DocC will still hide the parameter and return value documentation that doesn't apply to each source language's version of that symbol's page.
68+
69+
When the Swift representation returns `Void`---which corresponds to a `BOOL` return value in Objective-C (like in the example above)---DocC adds a generic description of the `BOOL` return value to the Objective-C version of that symbol's page.
70+
71+
@Row {
72+
@Column {
73+
![](params-2-swift)
74+
}
75+
@Column {
76+
![](params-2-objc)
77+
}
78+
}
79+
80+
When the Swift representation returns a value---which corresponds to a `nullable` return value in Objective-C---DocC extends your return value documentation, for the Objective-C version of that symbol's page, to describe that the methods returns `nil` if an error occurs unless your documentation already covers this behavior.
81+
For example, consider this throwing function in Swift and its corresponding Objective-C interface:
82+
83+
**Swift definition**
84+
85+
```swift
86+
/// - Parameters:
87+
/// - someValue: Some description of this parameter.
88+
/// - Returns: Some general description of this return value.
89+
@objc func doSomething(with someValue: Int) throws -> String
90+
```
91+
92+
**Generated Objective-C interface**
93+
94+
```objc
95+
- (nullable NSString *)doSomethingWith:(NSInteger)someValue
96+
error:(NSError **)error;
97+
```
98+
99+
For the Swift representation, with one parameter and a non-optional return value,
100+
DocC displays the "someValue" parameter documentation and return value documentation as-is.
101+
For the Objective-C representation, with two parameters and a nullable return value,
102+
DocC displays the "someValue" parameter documentation, generic "error" parameter documentation, and extends the return value documentation with a generic description about the Objective-C specific `nil` return value when the method encounters an error.
103+
104+
@Row {
105+
@Column {
106+
![](params-3-swift)
107+
}
108+
@Column {
109+
![](params-3-objc)
110+
}
111+
}
112+
113+
> Tip:
114+
> If you document the Objective-C specific `nil` return value for a method that corresponds to a throwing function in Swift,
115+
> but don't provide more information to the reader than "On failure, this method returns `nil`",
116+
> consider removing that written documentation to let DocC display its generic description about the Objective-C specific `nil` return value,
117+
> only on the Objective-C version of that symbol's page.
118+
119+
The return value documentation you write displays on both the Swift and Objective-C versions of that symbol's page.
120+
DocC won't add its generic `nil` return value description to the Objective-C page,
121+
if your return value documentation already describes that the method returns `nil` when it fails or encounters an error,
122+
but that Objective-C specific documentation you've written will display on the Swift version of that page where the symbol has a non-optional return type.
62123

63124
<!-- Copyright (c) 2024 Apple Inc and the Swift Project authors. All Rights Reserved. -->
Lines changed: 28 additions & 0 deletions
Loading
Lines changed: 27 additions & 0 deletions
Loading
Lines changed: 24 additions & 0 deletions
Loading
Lines changed: 22 additions & 0 deletions
Loading
Lines changed: 44 additions & 0 deletions
Loading
Lines changed: 40 additions & 0 deletions
Loading
Lines changed: 17 additions & 0 deletions
Loading
Lines changed: 15 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)