KT-12303 Pass only relevant annotations to annotation processors

(cherry picked from commit 01742aa)
This commit is contained in:
Yan Zhulanow
2016-07-13 16:48:09 +03:00
committed by Yan Zhulanow
parent 7810678389
commit 1a1eb7dcfa
17 changed files with 327 additions and 4 deletions
@@ -26,11 +26,11 @@ import javax.lang.model.element.TypeElement
import javax.tools.Diagnostic
import kotlin.properties.Delegates
public class AnnotationProcessorStub : AbstractProcessor() {
class AnnotationProcessorStub : AbstractProcessor() {
override fun process(annotations: Set<TypeElement>?, roundEnv: RoundEnvironment?) = true
}
public abstract class AnnotationProcessorWrapper(
abstract class AnnotationProcessorWrapper(
private val processorFqName: String,
private val taskQualifier: String
) : Processor {
@@ -38,6 +38,13 @@ public abstract class AnnotationProcessorWrapper(
private companion object {
val KAPT_ANNOTATION_OPTION = "kapt.annotations"
val KAPT_KOTLIN_GENERATED_OPTION = "kapt.kotlin.generated"
/*
* If no Java sources are provided, javac finishes without running Annotation Processing.
* This is not what we want, so we generate a special class for this case
* with a field annotated with KAPT_SPECIAL_ANNOTATION (see AnnotationProcessingManager.generateJavaHackFile).
*/
val KAPT_SPECIAL_ANNOTATION = "__gen.KotlinAptAnnotation"
}
private val processor: Processor by lazy {
@@ -56,6 +63,8 @@ public abstract class AnnotationProcessorWrapper(
private var roundCounter = 0
private var handledAnnotationTypes: Set<String> = emptySet()
override fun getCompletions(
element: Element?,
annotation: AnnotationMirror?,
@@ -83,11 +92,13 @@ public abstract class AnnotationProcessorWrapper(
}
processor.init(processingEnv)
handledAnnotationTypes = this.supportedAnnotationTypes
}
override fun getSupportedAnnotationTypes(): MutableSet<String> {
val supportedAnnotations = processor.supportedAnnotationTypes.toMutableSet()
supportedAnnotations.add("__gen.KotlinAptAnnotation")
supportedAnnotations.add(KAPT_SPECIAL_ANNOTATION)
return supportedAnnotations
}
@@ -106,7 +117,10 @@ public abstract class AnnotationProcessorWrapper(
if (roundCounter == 1) {
for (annotationFqName in kotlinAnnotationsProvider.annotatedKotlinElements.keys) {
if (annotationFqName in existingFqNames) continue
if (annotationFqName in existingFqNames
|| annotationFqName == KAPT_SPECIAL_ANNOTATION
|| annotationFqName !in handledAnnotationTypes // Filter out irrelevant annotations) continue
) continue
existingFqNames.add(annotationFqName)
processingEnv.elementUtils.getTypeElement(annotationFqName)?.let { wrappedAnnotations += it }
}
@@ -173,6 +173,16 @@ fun getSomething() = 10
}
}
@Test
fun testAndroidIcepickProject() {
val project = Project("AndroidIcepickProject", gradleVersion)
val options = defaultBuildOptions().copy(incremental = false)
project.build("assembleDebug", options = options) {
assertSuccessful()
}
}
@Test
fun testAndroidExtensions() {
val project = Project("AndroidExtensionsProject", gradleVersion)
@@ -0,0 +1,45 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'android-sdk-manager'
dependencies {
compile "frankiesardo:icepick:3.2.0"
kapt "frankiesardo:icepick-processor:3.2.0"
compile 'org.parceler:parceler-api:1.1.5'
kapt 'org.parceler:parceler:1.1.5'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.example.icepick.kotlin"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
lintOptions {
abortOnError false
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}
repositories {
mavenCentral()
maven {
url "https://clojars.org/repo/"
}
mavenLocal()
}
kapt {
generateStubs = true
}
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.frankiesardo.icepick"
android:versionCode="1"
android:versionName="1.0">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,28 @@
package com.github.frankiesardo.icepick
import android.content.Context
import android.os.Parcelable
import android.util.AttributeSet
import com.sample.icepick.lib.BaseCustomView
import icepick.State
class CustomView : BaseCustomView {
@JvmField @State
var textColor: Int? = null
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
fun setTextColorWithAnotherMethod(color: Int) {
this.textColor = color
setTextColor(textColor!!)
}
override fun onRestoreInstanceState(state: Parcelable) {
super.onRestoreInstanceState(state)
if (textColor != null) {
setTextColorWithAnotherMethod(textColor!!)
}
}
}
@@ -0,0 +1,19 @@
package com.github.frankiesardo.icepick
import org.parceler.Parcel
@Parcel
class Example {
lateinit var name: String
@JvmField
var age: Int = 0
constructor() { /*Required empty bean constructor*/
}
constructor(age: Int, name: String) {
this.age = age
this.name = name
}
}
@@ -0,0 +1,18 @@
package com.github.frankiesardo.icepick
import android.os.Bundle
import android.os.Parcelable
import org.parceler.Parcels
import icepick.Bundler
class ExampleBundler : Bundler<Any> {
override fun put(s: String, example: Any, bundle: Bundle) {
bundle.putParcelable(s, Parcels.wrap(example))
}
override fun get(s: String, bundle: Bundle): Any {
return Parcels.unwrap<Any>(bundle.getParcelable<Parcelable>(s))
}
}
@@ -0,0 +1,49 @@
package com.github.frankiesardo.icepick
import android.graphics.Color
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import com.sample.icepick.lib.BaseActivity
import icepick.State
class MainActivity : BaseActivity() {
@JvmField @State(MyBundler::class)
var message: String? = null
lateinit var customView: CustomView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
customView = findViewById(R.id.custom_view) as CustomView
updateText()
}
private fun updateText() {
val defaultText = if (message == null || baseMessage == null) {
"Use the menu to add some state"
} else {
baseMessage + message
}
customView.text = defaultText
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu)
return super.onPrepareOptionsMenu(menu)
}
override fun onMenuItemSelected(featureId: Int, item: MenuItem): Boolean {
if (item.itemId == R.id.action_add_state) {
customView.setBackgroundColorWithAnotherMethod(Color.BLUE)
customView.setTextColorWithAnotherMethod(Color.WHITE)
baseMessage = "This state will be automagically "
message = "saved and restored"
updateText()
return true
}
return super.onMenuItemSelected(featureId, item)
}
}
@@ -0,0 +1,17 @@
package com.github.frankiesardo.icepick
import android.os.Bundle
import icepick.Bundler
class MyBundler : Bundler<String> {
override fun put(key: String, value: String?, bundle: Bundle) {
if (value != null) {
bundle.putString(key, value + "*")
}
}
override fun get(key: String, bundle: Bundle): String? {
return bundle.getString(key)
}
}
@@ -0,0 +1,24 @@
package com.sample.icepick.lib
import android.app.Activity
import android.os.Bundle
import android.os.Parcelable
import icepick.Icepick
import icepick.State
import android.util.Log
open class BaseActivity : Activity() {
@JvmField @State
var baseMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Icepick.restoreInstanceState(this, savedInstanceState)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Icepick.saveInstanceState(this, outState)
}
}
@@ -0,0 +1,34 @@
package com.sample.icepick.lib
import android.content.Context
import android.os.Parcelable
import android.util.AttributeSet
import android.widget.TextView
import icepick.Icepick
import icepick.State
open class BaseCustomView : TextView {
@JvmField @State
var backgroundColor: Int? = null
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
fun setBackgroundColorWithAnotherMethod(color: Int) {
this.backgroundColor = color
setBackgroundColor(color)
}
override fun onSaveInstanceState(): Parcelable {
return Icepick.saveInstanceState(this, super.onSaveInstanceState())
}
override fun onRestoreInstanceState(state: Parcelable) {
super.onRestoreInstanceState(Icepick.restoreInstanceState(this, state))
if (backgroundColor != null) {
setBackgroundColorWithAnotherMethod(backgroundColor!!)
}
}
}
@@ -0,0 +1,12 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.frankiesardo.icepick.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:id="@+id/custom_view"/>
</LinearLayout>
@@ -0,0 +1,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_add_state"
android:title="@string/action_add_state"
android:orderInCategory="100"
android:showAsAction="never" />
</menu>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Icepick</string>
<string name="action_add_state">Add some state</string>
</resources>
@@ -0,0 +1,17 @@
buildscript {
ext.kotlin_version = '0.1-SNAPSHOT' //'1.0.3'
repositories {
mavenCentral()
mavenLocal()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:$androidToolsVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.jakewharton.sdkmanager:gradle-plugin:0.12.+"
}
}
task wrapper(type: Wrapper) {
gradleVersion = '2.12'
}
@@ -0,0 +1 @@
org.gradle.jvmargs=-ea -XX:MaxPermSize=512m