krzysztofzablocki / Sourcery

Meta-programming for Swift, stop writing boilerplate code.
http://merowing.info
MIT License
7.7k stars 621 forks source link

Correctly detecting enum rawValue type #18

Closed ilyapuchka closed 7 years ago

ilyapuchka commented 7 years ago

Currently enums assume that the first type after : is a rawValue type. But that will fail in a couple of scenarios. There are several different ways to define valid enum:

  1. Enum explicitly implementing RawRepresentable:
enum MyEnum: RawRepresentable { //not necessary first or present directly
  typealias RawValue: Int //not necessary present
  var rawValue: Int { ... } //type can be RawValue
  init?(rawValue: Int) { ... } //type can be RawValue
}
  1. Implicit rawValue enum
enum StringEnum: String {
  case a, b, c
}

enum NumericEnum: Int { //or any other numeric type
  case one, two, three
}
  1. Enum with no rawValue at all
enum JustEnum {
 case a, b, c
}

I can suggest the following logic:

  1. if there are no inherited types - enum does not have raw value
  2. if there are inherited types: 2.a if there is RawRepresentable at any position in inherited types: 2.a.i check type of rawValue property, or 2.a.ii check type of rawValue constructor argument, or 2.a.iii fail otherwise (as SourceKitten does not provide info about typealiases) or scan type body content for typealias 2.b if there is no RawReperesentable in inherited types get the first type as rawValue type if there is any

There are of course more scenarios that will still not work (like enum that implements protocol derived from RawRepresentable), but we can always improve in the future.

krzysztofzablocki commented 7 years ago

Seems like a sensible approach, in 2.a.iii let's do manual scan instead of failing since it's pretty straightforward, you can take a look at how I access src code in the Associated values for enums since that's not provided by.