Skip to content

Commit 74275e8

Browse files
Fixed nested type resolution in various cases (#1384)
Co-authored-by: Krzysztof Zabłocki <[email protected]>
1 parent b851897 commit 74275e8

File tree

5 files changed

+188
-62
lines changed

5 files changed

+188
-62
lines changed

Diff for: SourceryRuntime/Sources/Common/Composer/ParserResultsComposed.swift

+41-18
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ internal struct ParserResultsComposed {
2727
associatedTypes = Self.extractAssociatedTypes(parserResult)
2828
parsedTypes = parserResult.types
2929

30+
var moduleAndTypeNameCollisions: Set<String> = []
31+
32+
for type in parsedTypes where !type.isExtension && type.parent == nil {
33+
if let module = type.module, type.localName == module {
34+
moduleAndTypeNameCollisions.insert(module)
35+
}
36+
}
37+
3038
// set definedInType for all methods and variables
3139
parsedTypes
3240
.forEach { type in
@@ -36,16 +44,23 @@ internal struct ParserResultsComposed {
3644
}
3745

3846
// map all known types to their names
39-
parsedTypes
40-
.filter { !$0.isExtension }
41-
.forEach {
42-
typeMap[$0.globalName] = $0
43-
if let module = $0.module {
44-
var typesByModules = modules[module, default: [:]]
45-
typesByModules[$0.name] = $0
46-
modules[module] = typesByModules
47-
}
47+
48+
for type in parsedTypes where !type.isExtension && type.parent == nil {
49+
let name = type.name
50+
// If a type name has the `<module>.` prefix, and the type `<module>.<module>` is undefined, we can safely remove the `<module>.` prefix
51+
if let module = type.module, name.hasPrefix(module), name.dropFirst(module.count).hasPrefix("."), !moduleAndTypeNameCollisions.contains(module) {
52+
type.localName.removeFirst(module.count + 1)
4853
}
54+
}
55+
56+
for type in parsedTypes where !type.isExtension {
57+
typeMap[type.globalName] = type
58+
if let module = type.module {
59+
var typesByModules = modules[module, default: [:]]
60+
typesByModules[type.name] = type
61+
modules[module] = typesByModules
62+
}
63+
}
4964

5065
/// Resolve typealiases
5166
let typealiases = Array(unresolvedTypealiases.values)
@@ -66,9 +81,14 @@ internal struct ParserResultsComposed {
6681
types = unifyTypes()
6782
}
6883

69-
private func resolveExtensionOfNestedType(_ type: Type) {
84+
mutating private func resolveExtensionOfNestedType(_ type: Type) {
7085
var components = type.localName.components(separatedBy: ".")
71-
let rootName = type.module ?? components.removeFirst() // Module/parent name
86+
let rootName: String
87+
if type.parent != nil, let module = type.module {
88+
rootName = module
89+
} else {
90+
rootName = components.removeFirst()
91+
}
7292
if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] {
7393
type.localName = baseType.localName
7494
type.module = baseType.module
@@ -85,6 +105,14 @@ internal struct ParserResultsComposed {
85105
}
86106
}
87107
}
108+
// Parent extensions should always be processed before `type`, as this affects the globalName of `type`.
109+
for parent in type.parentTypes where parent.isExtension && parent.localName.contains(".") {
110+
let oldName = parent.globalName
111+
resolveExtensionOfNestedType(parent)
112+
if oldName != parent.globalName {
113+
rewriteChildren(of: parent)
114+
}
115+
}
88116
}
89117

90118
// if it had contained types, they might have been fully defined and so their name has to be noted in uniques
@@ -103,19 +131,14 @@ internal struct ParserResultsComposed {
103131
.forEach { (type: Type) in
104132
let oldName = type.globalName
105133

106-
let hasDotInLocalName = type.localName.contains(".") as Bool
107-
if let _ = type.parent, hasDotInLocalName {
134+
if type.localName.contains(".") {
108135
resolveExtensionOfNestedType(type)
109-
}
110-
111-
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
136+
} else if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
112137
var moduleName: String = ""
113138
if let module = type.module {
114139
moduleName = "\(module)."
115140
}
116141
type.localName = resolved.replacingOccurrences(of: moduleName, with: "")
117-
} else {
118-
return
119142
}
120143

121144
// nothing left to do

Diff for: SourceryRuntime/Sources/Generated/JSExport.generated.swift

-1
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,6 @@ extension Type: TypeAutoJSExport {}
673673
var set: SetType? { get }
674674
var asSource: String { get }
675675
var description: String { get }
676-
var hash: Int { get }
677676
var debugDescription: String { get }
678677
}
679678

Diff for: SourcerySwift/Sources/SourceryRuntime.content.generated.swift

+60-20
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,14 @@ internal struct ParserResultsComposed {
22462246
associatedTypes = Self.extractAssociatedTypes(parserResult)
22472247
parsedTypes = parserResult.types
22482248
2249+
var moduleAndTypeNameCollisions: Set<String> = []
2250+
2251+
for type in parsedTypes where !type.isExtension && type.parent == nil {
2252+
if let module = type.module, type.localName == module {
2253+
moduleAndTypeNameCollisions.insert(module)
2254+
}
2255+
}
2256+
22492257
// set definedInType for all methods and variables
22502258
parsedTypes
22512259
.forEach { type in
@@ -2255,16 +2263,23 @@ internal struct ParserResultsComposed {
22552263
}
22562264
22572265
// map all known types to their names
2258-
parsedTypes
2259-
.filter { !$0.isExtension }
2260-
.forEach {
2261-
typeMap[$0.globalName] = $0
2262-
if let module = $0.module {
2263-
var typesByModules = modules[module, default: [:]]
2264-
typesByModules[$0.name] = $0
2265-
modules[module] = typesByModules
2266-
}
2266+
2267+
for type in parsedTypes where !type.isExtension && type.parent == nil {
2268+
let name = type.name
2269+
// If a type name has the `<module>.` prefix, and the type `<module>.<module>` is undefined, we can safely remove the `<module>.` prefix
2270+
if let module = type.module, name.hasPrefix(module), name.dropFirst(module.count).hasPrefix("."), !moduleAndTypeNameCollisions.contains(module) {
2271+
type.localName.removeFirst(module.count + 1)
2272+
}
2273+
}
2274+
2275+
for type in parsedTypes where !type.isExtension {
2276+
typeMap[type.globalName] = type
2277+
if let module = type.module {
2278+
var typesByModules = modules[module, default: [:]]
2279+
typesByModules[type.name] = type
2280+
modules[module] = typesByModules
22672281
}
2282+
}
22682283
22692284
/// Resolve typealiases
22702285
let typealiases = Array(unresolvedTypealiases.values)
@@ -2274,15 +2289,25 @@ internal struct ParserResultsComposed {
22742289
22752290
/// Map associated types
22762291
associatedTypes.forEach {
2277-
typeMap[$0.key] = $0.value.type
2292+
if let globalName = $0.value.type?.globalName,
2293+
let type = typeMap[globalName] {
2294+
typeMap[$0.key] = type
2295+
} else {
2296+
typeMap[$0.key] = $0.value.type
2297+
}
22782298
}
22792299
22802300
types = unifyTypes()
22812301
}
22822302
2283-
private func resolveExtensionOfNestedType(_ type: Type) {
2303+
mutating private func resolveExtensionOfNestedType(_ type: Type) {
22842304
var components = type.localName.components(separatedBy: ".")
2285-
let rootName = type.module ?? components.removeFirst() // Module/parent name
2305+
let rootName: String
2306+
if type.parent != nil, let module = type.module {
2307+
rootName = module
2308+
} else {
2309+
rootName = components.removeFirst()
2310+
}
22862311
if let moduleTypes = modules[rootName], let baseType = moduleTypes[components.joined(separator: ".")] ?? moduleTypes[type.localName] {
22872312
type.localName = baseType.localName
22882313
type.module = baseType.module
@@ -2299,6 +2324,14 @@ internal struct ParserResultsComposed {
22992324
}
23002325
}
23012326
}
2327+
// Parent extensions should always be processed before `type`, as this affects the globalName of `type`.
2328+
for parent in type.parentTypes where parent.isExtension && parent.localName.contains(".") {
2329+
let oldName = parent.globalName
2330+
resolveExtensionOfNestedType(parent)
2331+
if oldName != parent.globalName {
2332+
rewriteChildren(of: parent)
2333+
}
2334+
}
23022335
}
23032336
23042337
// if it had contained types, they might have been fully defined and so their name has to be noted in uniques
@@ -2317,19 +2350,14 @@ internal struct ParserResultsComposed {
23172350
.forEach { (type: Type) in
23182351
let oldName = type.globalName
23192352
2320-
let hasDotInLocalName = type.localName.contains(".") as Bool
2321-
if let _ = type.parent, hasDotInLocalName {
2353+
if type.localName.contains(".") {
23222354
resolveExtensionOfNestedType(type)
2323-
}
2324-
2325-
if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
2355+
} else if let resolved = resolveGlobalName(for: oldName, containingType: type.parent, unique: typeMap, modules: modules, typealiases: resolvedTypealiases, associatedTypes: associatedTypes)?.name {
23262356
var moduleName: String = ""
23272357
if let module = type.module {
23282358
moduleName = "\\(module)."
23292359
}
23302360
type.localName = resolved.replacingOccurrences(of: moduleName, with: "")
2331-
} else {
2332-
return
23332361
}
23342362
23352363
// nothing left to do
@@ -3509,7 +3537,8 @@ public final class TemplateContext: NSObject, SourceryModel, NSCoding, Diffable
35093537
"based": types.based,
35103538
"inheriting": types.inheriting,
35113539
"implementing": types.implementing,
3512-
"protocolCompositions": types.protocolCompositions
3540+
"protocolCompositions": types.protocolCompositions,
3541+
"typealiases": types.typealiases
35133542
] as [String : Any],
35143543
"functions": functions,
35153544
"type": types.typesByName,
@@ -3547,6 +3576,9 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable {
35473576
35483577
/// module in which this typealias was declared
35493578
public var module: String?
3579+
3580+
/// Imports that existed in the file that contained this typealias declaration
3581+
public var imports: [Import] = []
35503582
35513583
/// typealias annotations
35523584
public var annotations: Annotations = [:]
@@ -3661,6 +3693,12 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable {
36613693
}; self.typeName = typeName
36623694
self.type = aDecoder.decode(forKey: "type")
36633695
self.module = aDecoder.decode(forKey: "module")
3696+
guard let imports: [Import] = aDecoder.decode(forKey: "imports") else {
3697+
withVaList(["imports"]) { arguments in
3698+
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
3699+
}
3700+
fatalError()
3701+
}; self.imports = imports
36643702
guard let annotations: Annotations = aDecoder.decode(forKey: "annotations") else {
36653703
withVaList(["annotations"]) { arguments in
36663704
NSException.raise(NSExceptionName.parseErrorException, format: "Key '%@' not found.", arguments: arguments)
@@ -3689,6 +3727,7 @@ public final class Typealias: NSObject, Typed, SourceryModel, Diffable {
36893727
aCoder.encode(self.typeName, forKey: "typeName")
36903728
aCoder.encode(self.type, forKey: "type")
36913729
aCoder.encode(self.module, forKey: "module")
3730+
aCoder.encode(self.imports, forKey: "imports")
36923731
aCoder.encode(self.annotations, forKey: "annotations")
36933732
aCoder.encode(self.documentation, forKey: "documentation")
36943733
aCoder.encode(self.parent, forKey: "parent")
@@ -8506,6 +8545,7 @@ extension TypeName: TypeNameAutoJSExport {}
85068545
var typeName: TypeName { get }
85078546
var type: Type? { get }
85088547
var module: String? { get }
8548+
var imports: [Import] { get }
85098549
var annotations: Annotations { get }
85108550
var documentation: Documentation { get }
85118551
var parent: Type? { get }

0 commit comments

Comments
 (0)