Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to disambiguate symbol links using type signature information #1095

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,74 +6,122 @@ Facilitate navigation between pages using links.

DocC supports the following link types to enable navigation between pages:

| Type | Usage |
| --- | --- |
| Symbol | Links to a symbol's reference page in your documentation. |
| Article | Links to an article or API collection in your documentation catalog. |
| Tutorial | Links to a tutorial in your documentation catalog. |
| Web | Links to an external URL. |
| Type | Usage
| -------- | -----
| Symbol | Links to a symbol's reference page in your documentation.
| Article | Links to an article or API collection in your documentation catalog.
| Tutorial | Links to a tutorial in your documentation catalog.
| Web | Links to an external URL.

### Navigate to a Symbol

To add a link to a symbol, wrap the symbol's name in a set of double backticks
(\`\`).
To add a link to a symbol in your module, wrap the symbol's name in a set of double backticks (\`\`):

```markdown
``SlothCreator``
``Sloth``
```

For nested symbols, include the path to the symbol in the link.
For links to member symbols or nested types, include the path to the symbol in the link:

```markdown
``SlothCreator/Sloth/eat(_:quantity:)``
``Sloth/eat(_:quantity:)``
``Sloth/Food``
```

DocC resolves symbol links relative to the context they appear in. For example,
a symbol link that appears inline in the `Sloth` class, and targets a
symbol in that class, can omit the `SlothCreator/Sloth/` portion of the symbol
path.
DocC resolves symbol links relative to the context that the link appears in.
This allows links in a type's documentation comment to omit the type's name from the symbol path when referring to its members.
For example, in the `Sloth` structure below, the `init(name:color:power:)` symbol link omits the `Sloth/` portion of the symbol path:

In some cases, a symbol's path isn't unique, such as with overloaded methods in
Swift. For example, consider the `Sloth` structure, which has multiple
`update(_:)` methods:
```swift
/// ...
/// You can create a sloth using ``init(name:color:power:)``.
public struct Sloth { // ╰──────────┬──────────╯
/// ... // ╰─────refers-to────╮
public init(name: String, color: Color, power: Power) { // ◁─╯
/* ... */
}
}
```

If DocC can't resolve a link in the current context, it gradually expands the search to the containing scope.
This allows links from one member to another member of the same type to omit the containing type's name from the symbol path.
For example, in the `Sloth` structure below,
the `eat(_:quantity:)` symbol link in the `energyLevel` property's documentation comment omits the `Sloth/` portion of the symbol path:

```swift
/// Updates the sloth's power.
///
/// - Parameter power: The sloth's new power.
mutating public func update(_ power: Power) {
self.power = power
/// ...
public struct Sloth {
/// ...
/// Restore the sloth's energy using ``eat(_:quantity:)``.
public var energyLevel = 10 // ╰───────┬──────╯
// │
/// ... // ╰──────refers-to─────╮
public mutating func eat(_ food: Food, quantity: Int) -> Int { // ◁─╯
/* ... */
}
}
```

/// Updates the sloth's energy level.
///
/// - Parameter energyLevel: The sloth's new energy level.
mutating public func update(_ energyLevel: Int) {
self.energyLevel = energyLevel
> Note:
If you prefer absolute symbol links you can prefix the symbol path with a leading slash followed by the name of the module to which that symbol belongs:
>
> ```markdown
> ``/SlothCreator/Sloth``
> ``/SlothCreator/Sloth/eat(_:quantity:)``
> ``/SlothCreator/Sloth/Food``
> ```
>
> DocC resolves absolute symbol links from the module's scope instead of the context that the link appears in.

Symbol paths are case-sensitive, meaning that symbols with the same name in different text casing are unambiguous.
For example, consider a `Sloth` structure with both a `color` property and a `Color` enumeration type:

```swift
public struct Sloth {
public var color: Color

public enum Color {
/* ... */
}
}
```

Both methods have an identical symbol path of `SlothCreator/Sloth/update(_:)`.
In this scenario, and to ensure uniqueness, DocC uses the symbol's unique
identifier instead of its name to disambiguate. DocC's warnings about ambiguous
symbol links suggests one disambiguation for each of the symbols that match the
ambiguous symbol path.
A ` ``Sloth/color`` ` symbol link unambiguously refers to the `color` property and a ` ``Sloth/Color`` ` symbol link unambiguously refers to the inner `Color` type.

#### Symbols with Multiple Language Representations

Symbol links to symbols that have representations in more than one programming language can use symbol paths in either source language.
For example, consider a `Sloth` class with `@objc` attributes:

```swift
@objc(TLASloth) public class Sloth: NSObject {
@objc public init(name: String, color: Color, power: Power) {
self.name = name
self.color = color
self.power = power
}
}
```

You can write a symbol link to the Sloth initializer using the symbol path in either source language:

**Swift name**

```markdown
### Updating Sloths
- ``Sloth/update(_:)-4ko57``
- ``Sloth/update(_:)-jixx``
``Sloth/init(name:color:power:)``
```

**Objective-C name**

```markdown
``TLASloth/initWithName:color:power:``
```

In the example above, both symbols are functions, so you need the unique
identifiers to disambiguate the `Sloth/update(_:)` link.
#### Ambiguous Symbol Links

Unique identifiers aren't the only way to disambiguate symbol links. If a symbol
has a different type from the other symbols with the same symbol path, you can
use that symbol's type suffix to disambiguate the link and make the link refer
to that symbol. For example, consider a `Color` structure with `red`, `green`,
and `blue` properties for color components and static properties for a handful
of predefined color values:
In some cases a symbol's path isn't unique.
This makes it ambiguous what specific symbol a symbol link refers to.
For example, consider a `Color` structure with `red`, `green`, and `blue` properties for color components and static properties for a handful of predefined color values:

```swift
public struct Color {
Expand All @@ -87,9 +135,8 @@ extension Color {
}
```

Both the `red` property and the `red` static property have a symbol path of
`Color/red`. Because these are different types of symbols you can disambiguate
`Color/red` with symbol type suffixes instead of the symbols' unique identifiers.
Both the `red` property and the `red` static property have a symbol path of `Color/red`.
Because these are different types of symbols you can disambiguate ` ``Color/red`` ` with a suffix indicating the symbol's type.

The following example shows a symbol link to the `red` property:

Expand All @@ -103,65 +150,146 @@ The following example shows a symbol link to the `red` static property:
``Color/red-type.property``
```

DocC supports the following symbol types for use in symbol links:
DocC supports the following symbol types as disambiguation in symbol links:

| Symbol type | Suffix |
|-------------------|-------------------|
| Enumeration | `-enum` |
| Enumeration case | `-enum.case` |
| Protocol | `-protocol` |
| Operator | `-func.op` |
| Typealias | `-typealias` |
| Function | `-func` |
| Associated Type | `-associatedtype` |
| Structure | `-struct` |
| Class | `-class` |
| Function | `-func` |
| Operator | `-func.op` |
| Property | `-property` |
| Type property | `-type.property` |
| Method | `-method` |
| Type method | `-type.method` |
| Subscript | `-subscript` |
| Type subscript | `-type.subscript` |
| Property | `-property` |
| Initializer | `-init` |
| Deinitializer | `-deinit` |
| Method | `-method` |
| Subscript | `-subscript` |
| Global variable | `-var` |
| Instance variable | `-ivar` |
| Macro | `-macro` |
| Module | `-module` |
| Namespace | `-namespace` |
| HTTP Request | `-httpRequest` |
| HTTP Parameter | `-httpParameter` |
| HTTP Response | `-httpResponse` |
| HTTPBody | `-httpBody` |
| Dictionary | `-dictionary` |
| Dictionary Key | `-dictionaryKey` |

Symbol type suffixes can include a source language identifier prefix — for
example, `-swift.enum` instead of `-enum`. However, the language
identifier doesn't disambiguate the link.
You can discover these symbol type suffixes from DocC's warnings about ambiguous symbol links.
DocC suggests one disambiguation for each of the symbols that match the ambiguous symbol path.

Symbol paths are case-sensitive, meaning that symbols with the same name in
different text casing don't need disambiguation.
Symbol type suffixes can include a source language identifier prefix---for example, `-swift.enum` instead of `-enum`.
However, the language identifier doesn't disambiguate the link.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it doesn't disambiguate the link, why would someone use this suffix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the first few releases of DocC (before Xcode 14.3) DocC required the language identifier prefix for unrelated and uninteresting implementation detail reasons, even though the that information wasn't useful for disambiguation purposes. Links created during those releases continue to work but can be shortened.


Symbols that have representations in both Swift and Objective-C can use
symbol paths in either source language. For example, consider a `Sloth`
class with `@objc` attributes:

In the example above, both symbols that match the ambiguous symbol path were different types of symbol.
If the symbols that match the ambiguous symbol path have are the same type of symbol,
such as with overloaded methods in Swift, a symbol type suffix won't disambiguate the link.
In this scenario, DocC uses information from the symbols' type signatures to disambiguate.
For example, consider the `Sloth` structure---from the SlothCreator example---which has two different `update(_:)` methods:

```swift
@objc(TLASloth) public class Sloth: NSObject {
@objc public init(name: String, color: Color, power: Power) {
self.name = name
self.color = color
self.power = power
}
/// Updates the sloth's power.
///
/// - Parameter power: The sloth's new power.
mutating public func update(_ power: Power) {
self.power = power
}

/// Updates the sloth's energy level.
///
/// - Parameter energyLevel: The sloth's new energy level.
mutating public func update(_ energyLevel: Int) {
self.energyLevel = energyLevel
}
```

You can write a symbol link to the Sloth initializer using the symbol path in either source language.
Both methods have an identical symbol path of `SlothCreator/Sloth/update(_:)`.
In this example there's only one parameter and its type is `Power` for the first overload and `Int` for the second overload.
DocC uses this parameter type information to suggest adding `(Power)` and `(Int)` to disambiguate each respective overload.

**Swift name**
The following example shows a topic group with disambiguated symbol links to both `Sloth/update(_:)` methods:

```markdown
``Sloth/init(name:color:power:)``
### Updating Sloths

- ``Sloth/update(_:)-(Power)``
- ``Sloth/update(_:)-(Int)``
```

**Objective-C name**
If there are more overloads with more parameters and return values,
DocC may suggest a combination of parameter types and return value types to uniquely disambiguate each overload.
For example consider a hypothetical weather service with these three overloads---with different parameter types and different return types---for a `forecast(for:at:)` method:

```swift
public func forecast(for days: DateInterval, at location: Location) -> HourByHourForecast { /* ... */ }
public func forecast(for day: Date, at location: Location) -> MinuteByMinuteForecast { /* ... */ }
public func forecast(for day: Date, at location: Location) -> HourByHourForecast { /* ... */ }
```

The first overload is the only one with where the first parameter has a `DateInterval` type.
The second parameter type isn't necessary to disambiguate the overload, and is the same in all three overloads,
so DocC suggests to add `(DateInterval,_)` to disambiguate the first overload.

The second overload is the only one with where the return value has a `MinuteByMinuteForecast` type,
so DocC suggests to add `‑>MinuteByMinuteForecast` to disambiguate the second overload.

The third overload has the same parameter types as the second overload and the same return value as the first overload,
so neither parameter types nor return types alone can uniquely disambiguate this overload.
In this scenario, DocC considers a combination of parameter types and return types to disambiguate the overload.
The first parameter type is different from the first overload and the return type is different from the second overload.
Together this information uniquely disambiguates the third overload,
so DocC suggests to add `(Date,_)‑>HourByHourForecast` to disambiguate the third overload.

You can discover the minimal combination of parameter types and return types for each overload from DocC's warnings about ambiguous symbol links.

The following example shows a topic group with disambiguated symbol links to the three `forecast(for:at:)` methods from before:

```markdown
``TLASloth/initWithName:color:power:``
### Requesting weather forecasts

- ``forecast(for:at:)-(DateInterval,_)``
- ``forecast(for:at:)->MinuteByMinuteForecast``
- ``forecast(for:at:)->(Date,_)->HourByHourForecast``
```

> Earlier Versions:
> Before Swift-DocC 6.1, disambiguation using parameter types or return types isn't supported.

If DocC can't disambiguate the symbol link using either a symbol type suffix or a combination parameter type names and return type names,
it will fall back to using a short hash of each symbol's unique identifier to disambiguate the symbol link.
You can discover these hashes from DocC's warnings about ambiguous symbol links.
The following example shows the same topic group with symbol links to the three `forecast(for:at:)` methods as before,
but using each symbol's unique identifier hash for disambiguation:

```markdown
### Requesting weather forecasts

- ``forecast(for:at:)-3brnk``
- ``forecast(for:at:)-4gcpg``
- ``forecast(for:at:)-7f3u``
```

The table below shows some examples of the types of link disambiguation suffixes that DocC supports:

| Disambiguation type | Example | Meaning
| ------------------------------- | --------------- | ------------
| Type of symbol | `-enum` | This symbol is an enumeration.
| Parameter type names | `-(Int,_,_)` | This symbol has three parameters and the first parameter is an `Int` value.
| ^ | `-()` | This symbol has no parameters.
| Return type names | `->String` | This symbol returns a `String` value.
| ^ | `->(_,_)` | This symbol returns a tuple with two elements.
| Parameter and return type names | `-(Bool)->()` | This symbol has one `Bool` parameter and no return value.
| Symbol identifier hash | `-4gcpg` | The hash of this symbol's unique identifier is "`4gcpg`".

### Navigate to an Article

To add a link to an article, use the less-than symbol (`<`), the `doc` keyword,
Expand Down