Skip to content

Commit

Permalink
Sidestep SourceKitten's off-by-one bug when parsing generic paramet…
Browse files Browse the repository at this point in the history
…er inheritance.
  • Loading branch information
MatyasKriz committed Jun 28, 2020
1 parent e2bb734 commit a0a7c82
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
38 changes: 34 additions & 4 deletions Generator/Source/CuckooGeneratorFramework/Tokenizer.swift
Expand Up @@ -99,6 +99,9 @@ public struct Tokenizer {
let children = subtokens.noneOf(Initializer.self)
let genericParameters = subtokens.only(GenericParameter.self)

// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
let fixedGenericParameters = fixSourceKittenLastGenericParameterBug(genericParameters)

return ProtocolDeclaration(
name: name,
accessibility: accessibility,
Expand All @@ -109,7 +112,7 @@ public struct Tokenizer {
children: children,
inheritedTypes: tokenizedInheritedTypes,
attributes: attributes,
genericParameters: genericParameters)
genericParameters: fixedGenericParameters)

case Kinds.ClassDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
Expand All @@ -124,6 +127,9 @@ public struct Tokenizer {
}
let genericParameters = subtokens.only(GenericParameter.self)

// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
let fixedGenericParameters = fixSourceKittenLastGenericParameterBug(genericParameters)

return ClassDeclaration(
name: name,
accessibility: accessibility,
Expand All @@ -134,7 +140,7 @@ public struct Tokenizer {
children: children,
inheritedTypes: tokenizedInheritedTypes,
attributes: attributes,
genericParameters: genericParameters)
genericParameters: fixedGenericParameters)

case Kinds.ExtensionDeclaration.rawValue:
return ExtensionDeclaration(range: range!)
Expand Down Expand Up @@ -185,6 +191,9 @@ public struct Tokenizer {
}
}

// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
let fixedGenericParameters = fixSourceKittenLastGenericParameterBug(genericParameters)

// When bodyRange != nil, we need to create `ClassMethod` instead of `ProtocolMethod`
if let bodyRange = bodyRange {
return ClassMethod(
Expand All @@ -196,7 +205,7 @@ public struct Tokenizer {
parameters: namedParameters,
bodyRange: bodyRange,
attributes: attributes,
genericParameters: genericParameters)
genericParameters: fixedGenericParameters)
} else {
return ProtocolMethod(
name: name,
Expand All @@ -206,7 +215,7 @@ public struct Tokenizer {
nameRange: nameRange!,
parameters: namedParameters,
attributes: attributes,
genericParameters: genericParameters)
genericParameters: fixedGenericParameters)
}

case Kinds.GenericParameter.rawValue:
Expand Down Expand Up @@ -292,6 +301,7 @@ public struct Tokenizer {
let inheritedTypeElement = (dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []).first
let inheritedType = (inheritedTypeElement as? [String: SourceKitRepresentable] ?? [:])[Key.Name.rawValue] as? String
let inheritanceDeclaration: InheritanceDeclaration?

if let inheritedType = inheritedType {
inheritanceDeclaration = .init(name: inheritedType)
} else {
Expand Down Expand Up @@ -468,6 +478,26 @@ public struct Tokenizer {

return ReturnSignature(throwString: throwString, returnType: returnType ?? WrappableType.type("Void"), whereConstraints: whereConstraints)
}

// FIXME: Remove when SourceKitten fixes the off-by-one error that includes the ending `>` in the last inherited type.
private func fixSourceKittenLastGenericParameterBug(_ genericParameters: [GenericParameter]) -> [GenericParameter] {
let fixedGenericParameters: [GenericParameter]
if let lastGenericParameter = genericParameters.last,
let inheritedType = lastGenericParameter.inheritedType,
inheritedType.name.hasSuffix(">>") == true {
fixedGenericParameters = genericParameters.dropLast() + [
GenericParameter(
name: lastGenericParameter.name,
range: lastGenericParameter.range.lowerBound..<lastGenericParameter.range.upperBound - 1,
inheritedType: InheritanceDeclaration(name: String(inheritedType.name.dropLast()))
)
]
} else {
fixedGenericParameters = genericParameters
}

return fixedGenericParameters
}
}

extension String {
Expand Down
4 changes: 4 additions & 0 deletions Tests/Swift/Source/GenericClass.swift
Expand Up @@ -22,6 +22,10 @@ class GenericClass<T: CustomStringConvertible, U: Codable & CustomStringConverti
readWritePropertyV = theV
}

func genericMethodParameter<G: GenericClass<T, U, V>>(g: G) {}

func genericMethodParameterNested<G: GenericClass<T, [Int], Array<String>>>(g: G) {}

func genericWhereMethodParameter<G>(g: G) where G: GenericClass<T, [Int], V> {}

func genericWhereMethodParameterNested<G>(g: G) where G: GenericClass<T, U, Array<String>> {}
Expand Down

0 comments on commit a0a7c82

Please sign in to comment.