@@ -194,7 +194,9 @@ extension ExtendedTypesFormatTransformation {
194194
195195 var ( extendedTypeSymbols,
196196 extensionBlockToExtendedTypeMapping,
197- extendedTypeToExtensionBlockMapping) = synthesizeExtendedTypeSymbols ( using: extensionBlockSymbols, extensionToRelationships)
197+ extendedTypeToExtensionBlockMapping) = synthesizePrimaryExtendedTypeSymbols ( using: extensionBlockSymbols, extensionToRelationships)
198+
199+ let contextOfRelationships = synthesizeSecondaryExtendedTypeSymbols ( & extendedTypeSymbols)
198200
199201 redirect ( \. target, of: & memberOfRelationships, using: extensionBlockToExtendedTypeMapping)
200202
@@ -217,12 +219,79 @@ extension ExtendedTypesFormatTransformation {
217219
218220 symbolGraph. relationships. append ( contentsOf: memberOfRelationships)
219221 symbolGraph. relationships. append ( contentsOf: conformsToRelationships)
222+ symbolGraph. relationships. append ( contentsOf: contextOfRelationships)
220223 extendedTypeSymbols. values. forEach { symbol in symbolGraph. symbols [ symbol. identifier. precise] = symbol }
221224
222- try synthesizeExtendedModuleSymbolsAndDeclaredInRelationships ( on: & symbolGraph, using: extendedTypeSymbols. values. map ( \. identifier. precise) )
225+ try synthesizeExtendedModuleSymbolsAndDeclaredInRelationships ( on: & symbolGraph, using: extendedTypeSymbols. values. filter { symbol in symbol . pathComponents . count == 2 } . map ( \. identifier. precise) )
223226
224227 return true
225228 }
229+
230+ private static func synthesizeSecondaryExtendedTypeSymbols( _ extendedTypeSymbols: inout [ String : SymbolGraph . Symbol ] ) -> [ SymbolGraph . Relationship ] {
231+ let sortedKeys : [ ( pathComponents: [ String ] , preciseId: String ) ] = extendedTypeSymbols. map { key, value in
232+ ( value. pathComponents, key)
233+ } . sorted ( by: { a, b in a. pathComponents. count <= b. pathComponents. count && a. preciseId < b. preciseId } )
234+
235+ var pathComponentsToSymbolIds : [ ArraySlice < String > : String ] = [ : ]
236+ pathComponentsToSymbolIds. reserveCapacity ( extendedTypeSymbols. count)
237+ for (key, symbol) in extendedTypeSymbols {
238+ pathComponentsToSymbolIds [ symbol. pathComponents [ 1 ... ] ] = key
239+ }
240+
241+ func lookupSymbol( _ pathComponents: ArraySlice < String > ) -> SymbolGraph . Symbol ? {
242+ guard let id = pathComponentsToSymbolIds [ pathComponents] else {
243+ return nil
244+ }
245+
246+ return extendedTypeSymbols [ id]
247+ }
248+
249+ var relationships = [ SymbolGraph . Relationship] ( )
250+ var symbolIsConnectedToParent = [ String: Bool] ( )
251+ symbolIsConnectedToParent. reserveCapacity ( extendedTypeSymbols. count)
252+
253+ for (pathComponents, preciseId) in sortedKeys {
254+ guard var symbol = extendedTypeSymbols [ preciseId] else {
255+ continue
256+ }
257+
258+ let modulePrefix = pathComponents [ 0 ]
259+ var pathComponents = pathComponents [ 1 ..< pathComponents. count- 1 ]
260+
261+ while !pathComponents. isEmpty {
262+ let parent = lookupSymbol ( pathComponents) ? . replacing ( \. accessLevel) { oldSymbol in
263+ max ( oldSymbol. accessLevel, symbol. accessLevel)
264+ } ?? SymbolGraph . Symbol ( identifier: . init( precise: " s:e: " + symbol. identifier. precise,
265+ interfaceLanguage: symbol. identifier. interfaceLanguage) ,
266+ names: . init( title: pathComponents. joined ( separator: " . " ) ,
267+ navigator: pathComponents. last? . asDeclarationFragment ( . identifier) ,
268+ subHeading: nil ,
269+ prose: nil ) ,
270+ pathComponents: [ modulePrefix] + pathComponents,
271+ docComment: nil ,
272+ accessLevel: symbol. accessLevel,
273+ kind: . unknownExtendedType,
274+ mixins: symbol. mixins. keeping ( SymbolGraph . Symbol. Swift. Extension. mixinKey) )
275+
276+
277+ pathComponentsToSymbolIds [ pathComponents] = parent. identifier. precise
278+ extendedTypeSymbols [ parent. identifier. precise] = parent
279+
280+ if !symbolIsConnectedToParent[ symbol. identifier. precise, default: false ] {
281+ relationships. append ( . init( source: symbol. identifier. precise,
282+ target: parent. identifier. precise,
283+ kind: . inContextOf,
284+ targetFallback: parent. title) )
285+ symbolIsConnectedToParent [ symbol. identifier. precise] = true
286+ }
287+
288+ symbol = parent
289+ pathComponents. removeLast ( )
290+ }
291+ }
292+
293+ return relationships
294+ }
226295
227296 /// Tries to obtain `docComment`s for all `targets` and copies the documentaiton from sources to the target.
228297 ///
@@ -344,7 +413,7 @@ extension ExtendedTypesFormatTransformation {
344413 ///
345414 /// - Returns: - the created extended type symbols keyed by their precise identifier, along with a bidirectional
346415 /// mapping between the extended type symbols and the `.extension` symbols
347- private static func synthesizeExtendedTypeSymbols < RS: Sequence > ( using extensionBlockSymbols: [ String : SymbolGraph . Symbol ] ,
416+ private static func synthesizePrimaryExtendedTypeSymbols < RS: Sequence > ( using extensionBlockSymbols: [ String : SymbolGraph . Symbol ] ,
348417 _ extensionToRelationships: RS )
349418 -> ( extendedTypeSymbols: [ String : SymbolGraph . Symbol ] ,
350419 extensionBlockToExtendedTypeMapping: [ String : String ] ,
@@ -354,10 +423,11 @@ extension ExtendedTypesFormatTransformation {
354423 var extendedTypeSymbols : [ String : SymbolGraph . Symbol ] = [ : ]
355424 var extensionBlockToExtendedTypeMapping : [ String : String ] = [ : ]
356425 var extendedTypeToExtensionBlockMapping : [ String : [ String ] ] = [ : ]
426+ var pathComponentToExtendedTypeMapping : [ ArraySlice < String > : String ] = [ : ]
357427
358428 extensionBlockToExtendedTypeMapping. reserveCapacity ( extensionBlockSymbols. count)
359429
360- let createExtendedTypeSymbol = { ( extensionBlockSymbol: SymbolGraph . Symbol , id: String ) -> SymbolGraph . Symbol in
430+ let createExtendedTypeSymbolAndAnchestors = { ( extensionBlockSymbol: SymbolGraph . Symbol , id: String ) -> SymbolGraph . Symbol in
361431 var newMixins = [ String: Mixin] ( )
362432
363433 if var swiftExtension = extensionBlockSymbol [ mixin: SymbolGraph . Symbol. Swift. Extension. self] {
@@ -408,13 +478,14 @@ extension ExtendedTypesFormatTransformation {
408478
409479 let symbol : SymbolGraph . Symbol = extendedTypeSymbols [ extendedSymbolId] ? . replacing ( \. accessLevel) { oldSymbol in
410480 max ( oldSymbol. accessLevel, extensionBlockSymbol. accessLevel)
411- } ?? createExtendedTypeSymbol ( extensionBlockSymbol, extendedSymbolId)
481+ } ?? createExtendedTypeSymbolAndAnchestors ( extensionBlockSymbol, extendedSymbolId)
482+
483+ pathComponentToExtendedTypeMapping [ symbol. pathComponents [ ... ] ] = symbol. identifier. precise
412484
413485 extendedTypeSymbols [ symbol. identifier. precise] = symbol
414486
415487 extensionBlockToExtendedTypeMapping [ extensionTo. source] = symbol. identifier. precise
416- extendedTypeToExtensionBlockMapping [ symbol. identifier. precise]
417- = ( extendedTypeToExtensionBlockMapping [ symbol. identifier. precise] ?? [ ] ) + [ extensionBlockSymbol. identifier. precise]
488+ extendedTypeToExtensionBlockMapping [ symbol. identifier. precise, default: [ ] ] += [ extensionBlockSymbol. identifier. precise]
418489 }
419490
420491 return ( extendedTypeSymbols, extensionBlockToExtendedTypeMapping, extendedTypeToExtensionBlockMapping)
@@ -522,3 +593,21 @@ private extension SymbolGraph.Relationship {
522593 return new
523594 }
524595}
596+
597+ private extension String {
598+ func asDeclarationFragment( _ kind: SymbolGraph . Symbol . DeclarationFragments . Fragment . Kind ) -> [ SymbolGraph . Symbol . DeclarationFragments . Fragment ] {
599+ [ . init( kind: kind, spelling: self , preciseIdentifier: nil ) ]
600+ }
601+ }
602+
603+ private extension Dictionary {
604+ func keeping( _ keys: Key ... ) -> Self {
605+ var new = Self ( )
606+
607+ for key in keys {
608+ new [ key] = self [ key]
609+ }
610+
611+ return new
612+ }
613+ }
0 commit comments