Sidestep `SourceKitten`'s off-by-one bug when parsing generic parameter inheritance.

This commit is contained in:
Matyáš Kříž 2020-06-28 16:45:16 +02:00
parent e2bb73412f
commit a0a7c82526
2 changed files with 38 additions and 4 deletions

View File

@ -99,6 +99,9 @@ public struct Tokenizer {
let children = subtokens.noneOf(Initializer.self) let children = subtokens.noneOf(Initializer.self)
let genericParameters = subtokens.only(GenericParameter.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( return ProtocolDeclaration(
name: name, name: name,
accessibility: accessibility, accessibility: accessibility,
@ -109,7 +112,7 @@ public struct Tokenizer {
children: children, children: children,
inheritedTypes: tokenizedInheritedTypes, inheritedTypes: tokenizedInheritedTypes,
attributes: attributes, attributes: attributes,
genericParameters: genericParameters) genericParameters: fixedGenericParameters)
case Kinds.ClassDeclaration.rawValue: case Kinds.ClassDeclaration.rawValue:
let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? []) let subtokens = tokenize(dictionary[Key.Substructure.rawValue] as? [SourceKitRepresentable] ?? [])
@ -124,6 +127,9 @@ public struct Tokenizer {
} }
let genericParameters = subtokens.only(GenericParameter.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 ClassDeclaration( return ClassDeclaration(
name: name, name: name,
accessibility: accessibility, accessibility: accessibility,
@ -134,7 +140,7 @@ public struct Tokenizer {
children: children, children: children,
inheritedTypes: tokenizedInheritedTypes, inheritedTypes: tokenizedInheritedTypes,
attributes: attributes, attributes: attributes,
genericParameters: genericParameters) genericParameters: fixedGenericParameters)
case Kinds.ExtensionDeclaration.rawValue: case Kinds.ExtensionDeclaration.rawValue:
return ExtensionDeclaration(range: range!) return ExtensionDeclaration(range: range!)
@ -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` // When bodyRange != nil, we need to create `ClassMethod` instead of `ProtocolMethod`
if let bodyRange = bodyRange { if let bodyRange = bodyRange {
return ClassMethod( return ClassMethod(
@ -196,7 +205,7 @@ public struct Tokenizer {
parameters: namedParameters, parameters: namedParameters,
bodyRange: bodyRange, bodyRange: bodyRange,
attributes: attributes, attributes: attributes,
genericParameters: genericParameters) genericParameters: fixedGenericParameters)
} else { } else {
return ProtocolMethod( return ProtocolMethod(
name: name, name: name,
@ -206,7 +215,7 @@ public struct Tokenizer {
nameRange: nameRange!, nameRange: nameRange!,
parameters: namedParameters, parameters: namedParameters,
attributes: attributes, attributes: attributes,
genericParameters: genericParameters) genericParameters: fixedGenericParameters)
} }
case Kinds.GenericParameter.rawValue: case Kinds.GenericParameter.rawValue:
@ -292,6 +301,7 @@ public struct Tokenizer {
let inheritedTypeElement = (dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []).first let inheritedTypeElement = (dictionary[Key.InheritedTypes.rawValue] as? [SourceKitRepresentable] ?? []).first
let inheritedType = (inheritedTypeElement as? [String: SourceKitRepresentable] ?? [:])[Key.Name.rawValue] as? String let inheritedType = (inheritedTypeElement as? [String: SourceKitRepresentable] ?? [:])[Key.Name.rawValue] as? String
let inheritanceDeclaration: InheritanceDeclaration? let inheritanceDeclaration: InheritanceDeclaration?
if let inheritedType = inheritedType { if let inheritedType = inheritedType {
inheritanceDeclaration = .init(name: inheritedType) inheritanceDeclaration = .init(name: inheritedType)
} else { } else {
@ -468,6 +478,26 @@ public struct Tokenizer {
return ReturnSignature(throwString: throwString, returnType: returnType ?? WrappableType.type("Void"), whereConstraints: whereConstraints) 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 { extension String {

View File

@ -22,6 +22,10 @@ class GenericClass<T: CustomStringConvertible, U: Codable & CustomStringConverti
readWritePropertyV = theV 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 genericWhereMethodParameter<G>(g: G) where G: GenericClass<T, [Int], V> {}
func genericWhereMethodParameterNested<G>(g: G) where G: GenericClass<T, U, Array<String>> {} func genericWhereMethodParameterNested<G>(g: G) where G: GenericClass<T, U, Array<String>> {}