@@ -1757,23 +1757,87 @@ extension SourceKitLSPServer {
1757
1757
position: req. position
1758
1758
)
1759
1759
)
1760
- let locations = try await symbols. asyncMap { ( symbol) -> [ Location ] in
1761
- if symbol. bestLocalDeclaration != nil && !( symbol. isDynamic ?? true )
1762
- && symbol. usr? . hasPrefix ( " s: " ) ?? false /* Swift symbols have USRs starting with s: */
1760
+
1761
+ let canonicalOriginatorLocation = await languageService. canonicalDeclarationPosition (
1762
+ of: req. position,
1763
+ in: req. textDocument. uri
1764
+ )
1765
+
1766
+ // Returns `true` if `location` points to the same declaration that the definition request was initiated from.
1767
+ @Sendable func isAtCanonicalOriginatorLocation( _ location: Location ) async -> Bool {
1768
+ guard location. uri == req. textDocument. uri, let canonicalOriginatorLocation else {
1769
+ return false
1770
+ }
1771
+ return await languageService. canonicalDeclarationPosition ( of: location. range. lowerBound, in: location. uri)
1772
+ == canonicalOriginatorLocation
1773
+ }
1774
+
1775
+ var locations = try await symbols. asyncMap { ( symbol) -> [ Location ] in
1776
+ var locations : [ Location ]
1777
+ if let bestLocalDeclaration = symbol. bestLocalDeclaration,
1778
+ !( symbol. isDynamic ?? true ) ,
1779
+ symbol. usr? . hasPrefix ( " s: " ) ?? false /* Swift symbols have USRs starting with s: */
1763
1780
{
1764
1781
// If we have a known non-dynamic symbol within Swift, we don't need to do an index lookup.
1765
1782
// For non-Swift symbols, we need to perform an index lookup because the best local declaration will point to
1766
- // a header file but jump-to-definition should prefer the implementation (there's the declaration request to jump
1767
- // to the function's declaration).
1768
- return [ symbol . bestLocalDeclaration ] . compactMap { $0 }
1783
+ // a header file but jump-to-definition should prefer the implementation (there's the declaration request to
1784
+ // jump to the function's declaration).
1785
+ locations = [ bestLocalDeclaration]
1786
+ } else {
1787
+ locations = try await self . definitionLocations (
1788
+ for: symbol,
1789
+ in: req. textDocument. uri,
1790
+ languageService: languageService
1791
+ )
1769
1792
}
1770
- return try await self . definitionLocations ( for: symbol, in: req. textDocument. uri, languageService: languageService)
1793
+
1794
+ // If the symbol's location is is where we initiated rename from, also show the declarations that the symbol
1795
+ // overrides.
1796
+ if let location = locations. only,
1797
+ let usr = symbol. usr,
1798
+ let index = workspace. index ( checkedFor: . deletedFiles) ,
1799
+ await isAtCanonicalOriginatorLocation ( location)
1800
+ {
1801
+ let baseUSRs = index. occurrences ( ofUSR: usr, roles: . overrideOf) . flatMap {
1802
+ $0. relations. filter { $0. roles. contains ( . overrideOf) } . map ( \. symbol. usr)
1803
+ }
1804
+ locations += baseUSRs. compactMap {
1805
+ guard let baseDeclOccurrence = index. primaryDefinitionOrDeclarationOccurrence ( ofUSR: $0) else {
1806
+ return nil
1807
+ }
1808
+ return indexToLSPLocation ( baseDeclOccurrence. location)
1809
+ }
1810
+ }
1811
+
1812
+ return locations
1771
1813
} . flatMap { $0 }
1814
+
1772
1815
// Remove any duplicate locations. We might end up with duplicate locations when performing a definition request
1773
1816
// on eg. `MyStruct()` when no explicit initializer is declared. In this case we get two symbol infos, one for the
1774
1817
// declaration of the `MyStruct` type and one for the initializer, which is implicit and thus has the location of
1775
1818
// the `MyStruct` declaration itself.
1776
- return locations. unique
1819
+ locations = locations. unique
1820
+
1821
+ // Try removing any results that would point back to the location we are currently at. This ensures that eg. in the
1822
+ // following case we only show line 2 when performing jump-to-definition on `TestImpl.doThing`.
1823
+ //
1824
+ // ```
1825
+ // protocol TestProtocol {
1826
+ // func doThing()
1827
+ // }
1828
+ // struct TestImpl: TestProtocol {
1829
+ // func doThing() { }
1830
+ // }
1831
+ // ```
1832
+ //
1833
+ // If this would result in no locations, don't apply the filter. This way, performing jump-to-definition in the
1834
+ // middle of a function's base name takes us to the base name start, indicating that jump-to-definition was able to
1835
+ // resolve the location and didn't fail.
1836
+ let nonOriginatorLocations = await locations. asyncFilter { await !isAtCanonicalOriginatorLocation( $0) }
1837
+ if !nonOriginatorLocations. isEmpty {
1838
+ locations = nonOriginatorLocations
1839
+ }
1840
+ return locations
1777
1841
}
1778
1842
1779
1843
func definition(
0 commit comments