Last active
February 22, 2019 07:44
-
-
Save malvinstn/f117a3c31b0a30658e72ed2cc95919da to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@AutoService(Processor::class) | |
class AnalyticsEventProcessor : KotlinAbstractProcessor(), KotlinMetadataUtils { | |
companion object { | |
private val ANNOTATION = AnalyticsEvent::class.java | |
} | |
... | |
override fun process( | |
annotations: Set<TypeElement>, | |
roundEnv: RoundEnvironment | |
): Boolean { | |
// Get all elements that has been annotated with our annotation | |
val annotatedElements = roundEnv.getElementsAnnotatedWith(ANNOTATION) | |
for (annotatedElement in annotatedElements) { | |
// Check if the annotatedElement is a Kotlin sealed class | |
val analyticsElement = getAnalyticsElement(annotatedElement) ?: continue | |
// Get all the declared inner class as our Analytics Event | |
val declaredAnalyticsEvents = getDeclaredAnalyticsEvents(analyticsElement) | |
} | |
return true | |
} | |
private fun getAnalyticsElement(element: Element): TypeElement? { | |
val kotlinMetadata = element.kotlinMetadata | |
if (kotlinMetadata !is KotlinClassMetadata || element !is TypeElement) { | |
// Not a Kotlin class | |
messager.printMessage( | |
Diagnostic.Kind.WARNING, | |
"$element is not a Kotlin class." | |
) | |
return null | |
} | |
val proto = kotlinMetadata.data.classProto | |
if (proto.modality != ProtoBuf.Modality.SEALED) { | |
// Is not a sealed class | |
messager.printMessage( | |
Diagnostic.Kind.WARNING, | |
"$element is not a sealed Kotlin class." | |
) | |
return null | |
} | |
return element | |
} | |
private fun getDeclaredAnalyticsEvents( | |
analyticsElement: TypeElement | |
): Map<ClassName, List<String>> { | |
val analyticsEvents = mutableMapOf<ClassName, List<String>>() | |
val supertype = analyticsElement.asType() | |
val enclosedElements = analyticsElement.enclosedElements | |
for (element in enclosedElements) { | |
val type = element.asType() | |
if (element !is TypeElement) { | |
// Inner element is not a class | |
messager.printMessage( | |
Diagnostic.Kind.WARNING, | |
"$element is not a kotlin class." | |
) | |
continue | |
} else if (!typeUtils.directSupertypes(type).contains(supertype)) { | |
// Inner class does not extend from the enclosing sealed class | |
messager.printMessage( | |
Diagnostic.Kind.WARNING, | |
"$element does not extend from $analyticsElement." | |
) | |
continue | |
} | |
val kotlinMetadata = element.kotlinMetadata as KotlinClassMetadata | |
// Make use of KotlinPoet's ClassName to easily get the class' name. | |
val eventClass = element.asClassName() | |
// Extract the primary constructor and its parameters as the event's parameters. | |
val proto = kotlinMetadata.data.classProto | |
val nameResolver = kotlinMetadata.data.nameResolver | |
if (proto.constructorCount == 0) { | |
messager.printMessage( | |
Diagnostic.Kind.WARNING, | |
"$element has no constructor." | |
) | |
continue | |
} | |
val mainConstructor = proto.constructorList[0] | |
val eventParameters = mainConstructor.valueParameterList | |
.map { valueParameter -> | |
// Resolve the constructor parameter's name | |
// using nameResolver. | |
nameResolver.getString(valueParameter.name) | |
} | |
analyticsEvents[eventClass] = eventParameters | |
} | |
return analyticsEvents | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment