kapt: Support inherited annotations in Kotlin plugin

This commit is contained in:
Yan Zhulanow
2015-06-23 16:45:09 +03:00
parent d6e37ad8c5
commit 09c3bd8699
3 changed files with 46 additions and 11 deletions
@@ -33,7 +33,7 @@ import java.util.regex.Pattern
import java.util.regex.PatternSyntaxException
import kotlin.properties.Delegates
public abstract class AnnotationCollectorExtensionBase() : ClassBuilderInterceptorExtension {
public abstract class AnnotationCollectorExtensionBase(val supportInheritedAnnotations: Boolean) : ClassBuilderInterceptorExtension {
private object RecordTypes {
val ANNOTATED_CLASS = "c"
@@ -42,6 +42,8 @@ public abstract class AnnotationCollectorExtensionBase() : ClassBuilderIntercept
val SHORTENED_ANNOTATION = "a"
val SHORTENED_PACKAGE_NAME = "p"
val CLASS_DECLARATION = "d"
}
protected abstract val annotationFilterList: List<String>?
@@ -126,8 +128,15 @@ public abstract class AnnotationCollectorExtensionBase() : ClassBuilderIntercept
superName: String,
interfaces: Array<out String>
) {
currentClassSimpleName = name.substringAfterLast('/')
currentPackageName = name.substringBeforeLast('/', "").replace('/', '.')
val currentClassSimpleName = name.substringAfterLast('/')
val currentPackageName = name.substringBeforeLast('/', "").replace('/', '.')
this.currentClassSimpleName = currentClassSimpleName
this.currentPackageName = currentPackageName
if (supportInheritedAnnotations) {
recordClass(currentPackageName, currentClassSimpleName)
}
super.defineClass(origin, version, access, name, signature, superName, interfaces)
}
@@ -170,6 +179,15 @@ public abstract class AnnotationCollectorExtensionBase() : ClassBuilderIntercept
else !annotationFqName.startsWith("kotlin.jvm.internal.") //apply to all
}
private fun recordClass(packageName: String, className: String) {
val packageNameId = if (!packageName.isEmpty())
shortenedPackageNameCache.save(packageName, writer)
else null
val outputClassName = getOutputClassName(packageNameId, className)
writer.write("${RecordTypes.CLASS_DECLARATION} $outputClassName\n")
}
private fun recordAnnotation(name: String?, type: String, annotationDesc: String) {
val annotationFqName = Type.getType(annotationDesc).getClassName()
if (!isAnnotationHandled(annotationFqName)) return
@@ -183,7 +201,7 @@ public abstract class AnnotationCollectorExtensionBase() : ClassBuilderIntercept
else null
val className = this.currentClassSimpleName!!
val outputClassName = if (packageNameId == null) className else "$packageNameId/$className"
val outputClassName = getOutputClassName(packageNameId, className)
val elementName = if (name != null) " $name" else ""
writer.write("$type $annotationId $outputClassName$elementName\n")
@@ -193,6 +211,10 @@ public abstract class AnnotationCollectorExtensionBase() : ClassBuilderIntercept
}
}
private fun getOutputClassName(packageNameId: String?, className: String): String {
return if (packageNameId == null) className else "$packageNameId/$className"
}
private fun String.compilePatternOpt(): Pattern? {
return try {
Pattern.compile(this)
@@ -220,8 +242,9 @@ public abstract class AnnotationCollectorExtensionBase() : ClassBuilderIntercept
public class AnnotationCollectorExtension(
override val annotationFilterList: List<String>? = null,
val outputFilename: String? = null
) : AnnotationCollectorExtensionBase() {
val outputFilename: String? = null,
supportInheritedAnnotations: Boolean
) : AnnotationCollectorExtensionBase(supportInheritedAnnotations) {
private var writerInternal: Writer? = null
@@ -51,6 +51,8 @@ public object AnnotationCollectorConfigurationKeys {
CompilerConfigurationKey.create<String>("annotation file name")
public val STUBS_PATH: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("stubs output directory")
public val INHERITED: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("support inherited annotations")
}
public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
@@ -64,12 +66,17 @@ public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
CliOption("output", "<path>", "File in which annotated declarations will be placed", required = false)
public val STUBS_PATH_OPTION: CliOption =
CliOption("stubs", "<path>", "Output path for stubs.", required = false)
CliOption("stubs", "<path>", "Output path for stubs", required = false)
public val INHERITED_ANNOTATIONS_OPTION: CliOption =
CliOption("inherited", "<true/false>",
"True if collecting Kotlin class names for inherited annotations is needed", required = false)
}
override val pluginId: String = ANNOTATION_COLLECTOR_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> = listOf(ANNOTATION_FILTER_LIST_OPTION, OUTPUT_FILENAME_OPTION, STUBS_PATH_OPTION)
override val pluginOptions: Collection<CliOption> =
listOf(ANNOTATION_FILTER_LIST_OPTION, OUTPUT_FILENAME_OPTION, STUBS_PATH_OPTION, INHERITED_ANNOTATIONS_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
@@ -79,6 +86,7 @@ public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
}
OUTPUT_FILENAME_OPTION -> configuration.put(AnnotationCollectorConfigurationKeys.OUTPUT_FILENAME, value)
STUBS_PATH_OPTION -> configuration.put(AnnotationCollectorConfigurationKeys.STUBS_PATH, value)
INHERITED_ANNOTATIONS_OPTION -> configuration.put(AnnotationCollectorConfigurationKeys.INHERITED, value)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
@@ -86,10 +94,12 @@ public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
public class AnnotationCollectorComponentRegistrar : ComponentRegistrar {
public override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val supportInheritedAnnotations = "true" == (configuration.get(AnnotationCollectorConfigurationKeys.INHERITED) ?: "true")
val annotationFilterList = configuration.get(AnnotationCollectorConfigurationKeys.ANNOTATION_FILTER_LIST)
val outputFilename = configuration.get(AnnotationCollectorConfigurationKeys.OUTPUT_FILENAME)
if (outputFilename != null) {
val collectorExtension = AnnotationCollectorExtension(annotationFilterList, outputFilename)
val collectorExtension = AnnotationCollectorExtension(annotationFilterList, outputFilename, supportInheritedAnnotations)
ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension)
}
@@ -55,7 +55,7 @@ public abstract class AbstractAnnotationProcessorBoxTest : CodegenTestCase() {
val environment = KotlinCoreEnvironment.createForTests(getTestRootDisposable()!!, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val project = environment.project
val collectorExtension = AnnotationCollectorExtensionForTests()
val collectorExtension = AnnotationCollectorExtensionForTests(false)
ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension)
myEnvironment = environment
@@ -63,7 +63,9 @@ public abstract class AbstractAnnotationProcessorBoxTest : CodegenTestCase() {
return collectorExtension
}
private class AnnotationCollectorExtensionForTests : AnnotationCollectorExtensionBase() {
private class AnnotationCollectorExtensionForTests(
supportInheritedAnnotations: Boolean
) : AnnotationCollectorExtensionBase(supportInheritedAnnotations) {
val stringWriter = StringWriter()
override fun getWriter(diagnostic: DiagnosticSink) = stringWriter