|
| 1 | +# Add a `filePath` property to `SourceLocation` |
| 2 | + |
| 3 | +* Proposal: [ST-NNNN](NNNN-sourcelocation-filepath.md) |
| 4 | +* Authors: [Jonathan Grynspan](https://github.com/grynspan) |
| 5 | +* Review Manager: TBD |
| 6 | +* Status: **Awaiting review** |
| 7 | +* Bug: rdar://152999195 |
| 8 | +* Implementation: [swiftlang/swift-testing#1334](https://github.com/swiftlang/swift-testing/pull/1334), [swiftlang/swift-testing#1472](https://github.com/swiftlang/swift-testing/pull/1472) |
| 9 | +* Review: ([pitch](https://forums.swift.org/t/pitch-add-a-filepath-property-to-sourcelocation-in-swift-testing/83995)) |
| 10 | + |
| 11 | +## Introduction |
| 12 | + |
| 13 | +Swift Testing represents the in-source location of tests, issues, errors, etc. |
| 14 | +using a structure called [`SourceLocation`](https://developer.apple.com/documentation/testing/sourcelocation). |
| 15 | +This structure contains the line, column, and file ID for a given location in a |
| 16 | +Swift source file. I propose adding the file _path_ to this structure for use by |
| 17 | +developers and tools. |
| 18 | + |
| 19 | +## Motivation |
| 20 | + |
| 21 | +When we initially designed Swift Testing and `SourceLocation`, our expectation |
| 22 | +was that tools like Visual Studio Code or Xcode would be able to translate Swift |
| 23 | +file IDs to file paths where needed. |
| 24 | + |
| 25 | +At the time, Swift 6 had not yet been introduced and we were working off the |
| 26 | +assumption that `#filePath` would eventually be deprecated (possibly in Swift 6). |
| 27 | +This assumption was based on the history behind `#fileID`: |
| 28 | + |
| 29 | +- [SE-0274](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0274-magic-file.md) |
| 30 | + originally proposed repurposing `#file` to generate file IDs (and added |
| 31 | + `#filePath` for use cases that still needed full paths.) |
| 32 | +- [SE-0285](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0285-ease-pound-file-transition.md) |
| 33 | + modified the plan to leave `#file` as-is in Swift 5 and introduced `#fileID` |
| 34 | + and planned to have `#file` equal `#fileID` in Swift 6 onward. |
| 35 | +- In September 2024, the Language Steering Group [discussed](https://forums.swift.org/t/file-vs-fileid-in-swift-6/74614/4) |
| 36 | + `#file`, `#filePath`, and `#fileID`, and decided to maintain the status quo. |
| 37 | + |
| 38 | +Because the future of these magic values (now expression macros) was unclear, we |
| 39 | +opted to provide only a `fileID` property on `SourceLocation`. `SourceLocation` |
| 40 | +_does_ gather a full file path, but does not expose a public property to access |
| 41 | +this value at runtime or later. |
| 42 | + |
| 43 | +It has become clear since we shipped Swift Testing that tools are much better |
| 44 | +equipped to handle file paths than Swift file IDs, and the translation from a |
| 45 | +file ID back to the original path on a developer's system may be non-trivial or |
| 46 | +even impossible (in the case of strict sandboxing around a tool). |
| 47 | + |
| 48 | +## Proposed solution |
| 49 | + |
| 50 | +I propose adding a `filePath` property to `SourceLocation` and to the JSON event |
| 51 | +stream schema. |
| 52 | + |
| 53 | +## Detailed design |
| 54 | + |
| 55 | +The following property is added: |
| 56 | + |
| 57 | +```swift |
| 58 | +extension SourceLocation { |
| 59 | + /// The path to the source file. |
| 60 | + public var filePath: String { get set } |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +Swift Testing's JSON schema (version `"6.3"` onward) is updated to add a |
| 65 | +`"filePath"` key to source location values and to make the `"fileID"` key |
| 66 | +optional: |
| 67 | + |
| 68 | +```diff |
| 69 | + <source-location> ::= { |
| 70 | +- "fileID": <string>, ; the Swift file ID of the file |
| 71 | ++ ["fileID": <string>,] ; the Swift file ID of the file if available, as per |
| 72 | ++ ; SE-0274 § "Specification of the #file string format" |
| 73 | ++ "filePath": <string>, ; the compile-time path to the file |
| 74 | + "line": <number>, |
| 75 | + "column": <number>, |
| 76 | + } |
| 77 | +``` |
| 78 | + |
| 79 | +The value of the `"filePath"` key is an absolute file system path. It is _not_ |
| 80 | +guaranteed to refer to an existing file (for instance, it may refer to a file on |
| 81 | +a build system that isn't present at runtime). The path style used (POSIX, |
| 82 | +Windows, or otherwise) is implementation-defined. |
| 83 | + |
| 84 | +If the `"fileID"` key is not present when Swift Testing decodes an instance of |
| 85 | +`SourceLocation`, it is synthesized from `"filePath"` and the module name is |
| 86 | +assumed to be `"__C"`[^cModuleName]. This change allows Swift Testing to support source |
| 87 | +location information generated in other languages like Objective-C or C++. For |
| 88 | +example, a test written in Objective-C could construct a `<source-location>` |
| 89 | +JSON value as follows: |
| 90 | + |
| 91 | +```objc |
| 92 | +id jsonObject = @{ |
| 93 | + @"line": @(__LINE__), |
| 94 | + @"column": @(__builtin_COLUMN()), |
| 95 | + @"filePath": @(__file__) |
| 96 | +}; |
| 97 | +``` |
| 98 | + |
| 99 | +And, assuming `__file__` equals `"/foo/bar/quux.m"`, Swift Testing would infer a |
| 100 | +file ID of `"__C/quux.m"`. |
| 101 | + |
| 102 | +[^cModuleName]: The Swift compiler and runtime assume a module name of `__C` for |
| 103 | + most imported foreign types. |
| 104 | + |
| 105 | +## Source compatibility |
| 106 | + |
| 107 | +There are no source compatibility concerns. |
| 108 | + |
| 109 | +## Integration with supporting tools |
| 110 | + |
| 111 | +Supporting tools will be able to migrate from the unsupported `"_filePath"` JSON |
| 112 | +key to the new `"filePath"` key. We will continue to emit `"_filePath"` where |
| 113 | +needed until the ecosystem has moved to `"filePath"`. |
| 114 | + |
| 115 | +## Future directions |
| 116 | + |
| 117 | +N/A |
| 118 | + |
| 119 | +## Alternatives considered |
| 120 | + |
| 121 | +- None. |
0 commit comments