override fun consume()

in sample/plugins-compiler/plugins-compiler/kotlin/src/main/kotlin/com/uber/crumb/sample/pluginscompiler/PluginsCompiler.kt [84:179]


  override fun consume(context: CrumbContext,
      type: TypeElement,
      annotations: Collection<AnnotationMirror>,
      metadata: Set<ConsumerMetadata>) {

    // Must be a type that supports extension values
    if (type.kind != CLASS) {
      context.processingEnv
          .messager
          .printMessage(ERROR,
              "@${PluginPoint::class.java.simpleName} is only applicable on classes when consuming!",
              type)
      return
    }

    val kmetadata = type.kotlinMetadata

    if (kmetadata == null
        && type.annotationMirrors.any {
          MoreElements.asType(it.annotationType.asElement()).qualifiedName.toString() == METADATA_FQCN
        }) {
      context.processingEnv
          .messager
          .printMessage(ERROR,
              "Metadata annotation was unreadable on $type. Please ensure the kotlin standard library is a " +
                  "dependency of this project.",
              type)
      return
    }

    if (kmetadata !is KotlinClassMetadata) {
      context.processingEnv
          .messager
          .printMessage(ERROR,
              "@${PluginPoint::class.java.simpleName} can't be applied to $type: must be a class.",
              type)
      return
    }

    val classData = kmetadata.data
    val (nameResolver, classProto) = classData

    // Must be an object class.
    if (classProto.classKind != ProtoBuf.Class.Kind.OBJECT) {
      context.processingEnv
          .messager
          .printMessage(ERROR,
              "@${PluginPoint::class.java.simpleName} can't be applied to $type: must be a Kotlin object class",
              type)
      return
    }

    val packageName = nameResolver.getString(classProto.fqName)
        .substringBeforeLast('/')
        .replace('/', '.')

    // Read the pluginpoint's target type, e.g. "MyPluginInterface"
    val pluginPoint = type.getAnnotation(PluginPoint::class.java)
    val targetPlugin: TypeMirror = try {
      pluginPoint.value
      throw IllegalStateException("This shouldn't actually happen")
    } catch (e: MirroredTypesException) {
      e.typeMirrors[0]
    }

    // List of plugin TypeElements
    val pluginClasses = metadata
        .mapNotNull { it[METADATA_KEY] }
        .map { pluginClass -> context.processingEnv.elementUtils.getTypeElement(pluginClass) }
        .filter {
          context
              .processingEnv
              .typeUtils
              .isAssignable(it.asType(), targetPlugin)
        }
        .toSet()

    val initializerCode = "return setOf(${pluginClasses.joinToString { "%T()" }})"
    val initializerValues = pluginClasses
        .map { it.asClassName() }
        .toTypedArray()
    val pluginsFunction = FunSpec.builder("obtain")
        .receiver(type.asClassName())
        .returns(Set::class.asClassName().parameterizedBy(
            targetPlugin.asTypeName()))
        .addStatement(initializerCode, *initializerValues)
        .build()

    // Generate the file
    val generatedDir = context.processingEnv.options[kaptGeneratedOption]?.let(::File)
        ?: throw IllegalStateException("Could not resolve kotlin generated directory!")
    FileSpec.builder(packageName, "${type.simpleName}_Plugins")
        .addFunction(pluginsFunction)
        .build()
        .writeTo(generatedDir)
  }