@@ -2037,6 +2037,71 @@ class PathHierarchyTests: XCTestCase {
20372037 try assertFindsPath ( " doSomething()-9kd0v " , in: tree, asSymbolID: " some-function-id-AnyObject " )
20382038 }
20392039
2040+ func testParameterDisambiguationWithKeyPathType( ) async throws {
2041+ // Create two overloads with different key path parameter types
2042+ let parameterTypes : [ SymbolGraph . Symbol . DeclarationFragments . Fragment ] = [
2043+ // Swift.Int
2044+ . init( kind: . typeIdentifier, spelling: " Int " , preciseIdentifier: " s:Si " ) ,
2045+ // Swift.Bool
2046+ . init( kind: . typeIdentifier, spelling: " Bool " , preciseIdentifier: " s:Sb " ) ,
2047+ ]
2048+
2049+ let catalog = Folder ( name: " CatalogName.docc " , content: [
2050+ JSONFile ( name: " ModuleName.symbols.json " , content: makeSymbolGraph ( moduleName: " ModuleName " , symbols: parameterTypes. map { parameterTypeFragment in
2051+ makeSymbol ( id: " some-function-id- \( parameterTypeFragment. spelling) -KeyPath " , kind: . func, pathComponents: [ " doSomething(keyPath:) " ] , signature: . init(
2052+ parameters: [
2053+ // "keyPath: KeyPath<String, Int>" or "keyPath: KeyPath<String, Bool>"
2054+ . init( name: " keyPath " , externalName: nil , declarationFragments: [
2055+ . init( kind: . identifier, spelling: " keyPath " , preciseIdentifier: nil ) ,
2056+ . init( kind: . text, spelling: " : " , preciseIdentifier: nil ) ,
2057+ . init( kind: . typeIdentifier, spelling: " KeyPath " , preciseIdentifier: " s:s7KeyPathC " ) ,
2058+ . init( kind: . text, spelling: " < " , preciseIdentifier: nil ) ,
2059+ . init( kind: . typeIdentifier, spelling: " String " , preciseIdentifier: " s:SS " ) ,
2060+ . init( kind: . text, spelling: " , " , preciseIdentifier: nil ) ,
2061+ parameterTypeFragment,
2062+ . init( kind: . text, spelling: " > " , preciseIdentifier: nil )
2063+ ] , children: [ ] )
2064+ ] ,
2065+ returns: [
2066+ . init( kind: . text, spelling: " () " , preciseIdentifier: nil ) // 'Void' in text representation
2067+ ]
2068+ ) )
2069+ } ) ) ,
2070+ ] )
2071+ let ( _, context) = try await loadBundle ( catalog: catalog)
2072+ let tree = context. linkResolver. localResolver. pathHierarchy
2073+
2074+ XCTAssert ( context. problems. isEmpty, " Unexpected problems \( context. problems. map ( \. diagnostic. summary) ) " )
2075+
2076+ let paths = tree. caseInsensitiveDisambiguatedPaths ( )
2077+
2078+ XCTAssertEqual ( paths [ " some-function-id-Int-KeyPath " ] , " /ModuleName/doSomething(keyPath:)-(KeyPath<String,Int>) " )
2079+ XCTAssertEqual ( paths [ " some-function-id-Bool-KeyPath " ] , " /ModuleName/doSomething(keyPath:)-(KeyPath<String,Bool>) " )
2080+
2081+ try assertPathCollision ( " doSomething(keyPath:) " , in: tree, collisions: [
2082+ ( " some-function-id-Int-KeyPath " , " -(KeyPath<String,Int>) " ) ,
2083+ ( " some-function-id-Bool-KeyPath " , " -(KeyPath<String,Bool>) " ) ,
2084+ ] )
2085+
2086+ try assertPathRaisesErrorMessage ( " doSomething(keyPath:) " , in: tree, context: context, expectedErrorMessage: " 'doSomething(keyPath:)' is ambiguous at '/ModuleName' " ) { error in
2087+ XCTAssertEqual ( error. solutions. count, 2 )
2088+
2089+ // These test symbols don't have full declarations. A real solution would display enough information to distinguish these.
2090+ XCTAssertEqual ( error. solutions. dropFirst ( 0 ) . first, . init( summary: " Insert '-(KeyPath<String,Bool>)' for \n 'doSomething(keyPath:)' " , replacements: [ ( " -(KeyPath<String,Bool>) " , 21 , 21 ) ] ) )
2091+ XCTAssertEqual ( error. solutions. dropFirst ( 1 ) . first, . init( summary: " Insert '-(KeyPath<String,Int>)' for \n 'doSomething(keyPath:)' " /* the test symbols don't have full declarations */, replacements: [ ( " -(KeyPath<String,Int>) " , 21 , 21 ) ] ) )
2092+ }
2093+
2094+ assertParsedPathComponents ( " doSomething(keyPath:)-(KeyPath<String,Int>) " , [ ( " doSomething(keyPath:) " , . typeSignature( parameterTypes: [ " KeyPath<String,Int> " ] , returnTypes: nil ) ) ] )
2095+ try assertFindsPath ( " doSomething(keyPath:)-(KeyPath<String,Int>) " , in: tree, asSymbolID: " some-function-id-Int-KeyPath " )
2096+ try assertFindsPath ( " doSomething(keyPath:)-(KeyPath<String,Int>)->() " , in: tree, asSymbolID: " some-function-id-Int-KeyPath " )
2097+ try assertFindsPath ( " doSomething(keyPath:)-2zg7h " , in: tree, asSymbolID: " some-function-id-Int-KeyPath " )
2098+
2099+ assertParsedPathComponents ( " doSomething(keyPath:)-(KeyPath<String,Bool>) " , [ ( " doSomething(keyPath:) " , . typeSignature( parameterTypes: [ " KeyPath<String,Bool> " ] , returnTypes: nil ) ) ] )
2100+ try assertFindsPath ( " doSomething(keyPath:)-(KeyPath<String,Bool>) " , in: tree, asSymbolID: " some-function-id-Bool-KeyPath " )
2101+ try assertFindsPath ( " doSomething(keyPath:)-(KeyPath<String,Bool>)->() " , in: tree, asSymbolID: " some-function-id-Bool-KeyPath " )
2102+ try assertFindsPath ( " doSomething(keyPath:)-2frrn " , in: tree, asSymbolID: " some-function-id-Bool-KeyPath " )
2103+ }
2104+
20402105 func testOverloadGroupSymbolsResolveLinksWithoutHash( ) async throws {
20412106 enableFeatureFlag ( \. isExperimentalOverloadedSymbolPresentationEnabled)
20422107
@@ -4404,6 +4469,26 @@ class PathHierarchyTests: XCTestCase {
44044469 }
44054470
44064471 assertParsedPathComponents ( " operator[]-(std::string&)->std::string& " , [ ( " operator[] " , . typeSignature( parameterTypes: [ " std::string& " ] , returnTypes: [ " std::string& " ] ) ) ] )
4472+
4473+ // Nested generic types
4474+ assertParsedPathComponents ( " functionName-(KeyPath<String,Int>) " , [ ( " functionName " , . typeSignature( parameterTypes: [ " KeyPath<String,Int> " ] , returnTypes: nil ) ) ] )
4475+ assertParsedPathComponents ( " functionName->KeyPath<String,Int> " , [ ( " functionName " , . typeSignature( parameterTypes: nil , returnTypes: [ " KeyPath<String,Int> " ] ) ) ] )
4476+
4477+ assertParsedPathComponents ( " functionName-(KeyPath<String,Int>,Dictionary<Int,Int>) " , [ ( " functionName " , . typeSignature( parameterTypes: [ " KeyPath<String,Int> " , " Dictionary<Int,Int> " ] , returnTypes: nil ) ) ] )
4478+ assertParsedPathComponents ( " functionName->(KeyPath<String,Int>,Dictionary<Int,Int>) " , [ ( " functionName " , . typeSignature( parameterTypes: nil , returnTypes: [ " KeyPath<String,Int> " , " Dictionary<Int,Int> " ] ) ) ] )
4479+
4480+ assertParsedPathComponents ( " functionName-(KeyPath<String,Dictionary<Int,Int>>) " , [ ( " functionName " , . typeSignature( parameterTypes: [ " KeyPath<String,Dictionary<Int,Int>> " ] , returnTypes: nil ) ) ] )
4481+ assertParsedPathComponents ( " functionName->KeyPath<String,Dictionary<Int,Int>> " , [ ( " functionName " , . typeSignature( parameterTypes: nil , returnTypes: [ " KeyPath<String,Dictionary<Int,Int>> " ] ) ) ] )
4482+
4483+ assertParsedPathComponents ( " functionName-(KeyPath<Array<Bool>,Dictionary<Int,(Bool,Bool))>>) " , [ ( " functionName " , . typeSignature( parameterTypes: [ " KeyPath<Array<Bool>,Dictionary<Int,(Bool,Bool))>> " ] , returnTypes: nil ) ) ] )
4484+ assertParsedPathComponents ( " functionName->KeyPath<Array<Bool>,Dictionary<Int,(Bool,Bool))>> " , [ ( " functionName " , . typeSignature( parameterTypes: nil , returnTypes: [ " KeyPath<Array<Bool>,Dictionary<Int,(Bool,Bool))>> " ] ) ) ] )
4485+
4486+ // Nested generics and tuple types
4487+ assertParsedPathComponents ( " functionName-(A<B,C>,(D<E,F,G>,H<(I,J),(K,L)>),M<N,(O<P,Q>,R),S>) " , [ ( " functionName " , . typeSignature( parameterTypes: [ " A<B,C> " , " (D<E,F,G>,H<(I,J),(K,L)>) " , " M<N,(O<P,Q>,R),S> " ] , returnTypes: nil ) ) ] )
4488+ assertParsedPathComponents ( " functionName->(A<B,C>,(D<E,F,G>,H<(I,J),(K,L)>),M<N,(O<P,Q>,R),S>) " , [ ( " functionName " , . typeSignature( parameterTypes: nil , returnTypes: [ " A<B,C> " , " (D<E,F,G>,H<(I,J),(K,L)>) " , " M<N,(O<P,Q>,R),S> " ] ) ) ] )
4489+ // With special characters
4490+ assertParsedPathComponents ( " functionName-(Å<𝔹,©>,(Δ<∃,⨍,𝄞>,ℌ<(𝓲,ⅉ),(🄺,ƛ)>),𝔐<𝚗,(Ω<π,Ⓠ>,℟),𝔖>) " , [ ( " functionName " , . typeSignature( parameterTypes: [ " Å<𝔹,©> " , " (Δ<∃,⨍,𝄞>,ℌ<(𝓲,ⅉ),(🄺,ƛ)>) " , " 𝔐<𝚗,(Ω<π,Ⓠ>,℟),𝔖> " ] , returnTypes: nil ) ) ] )
4491+ assertParsedPathComponents ( " functionName->(Å<𝔹,©>,(Δ<∃,⨍,𝄞>,ℌ<(𝓲,ⅉ),(🄺,ƛ)>),𝔐<𝚗,(Ω<π,Ⓠ>,℟),𝔖>) " , [ ( " functionName " , . typeSignature( parameterTypes: nil , returnTypes: [ " Å<𝔹,©> " , " (Δ<∃,⨍,𝄞>,ℌ<(𝓲,ⅉ),(🄺,ƛ)>) " , " 𝔐<𝚗,(Ω<π,Ⓠ>,℟),𝔖> " ] ) ) ] )
44074492 }
44084493
44094494 func testResolveExternalLinkFromTechnologyRoot( ) async throws {
0 commit comments