Kapt: Remove annotation processor wrappers for kapt1 (it's obsolete now)
This commit is contained in:
@@ -2,7 +2,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
|
||||
description = "Annotation Processor wrapper for Kotlin"
|
||||
description = "Kapt - Annotation processing for Kotlin"
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
@@ -12,12 +12,6 @@ val packedJars by configurations.creating
|
||||
|
||||
dependencies {
|
||||
compile(projectDist(":kotlin-stdlib"))
|
||||
compileOnly(project(":kotlin-annotation-processing"))
|
||||
compileOnly(gradleApi())
|
||||
testCompile(gradleApi())
|
||||
compileOnly("com.android.tools.build:gradle:1.1.0")
|
||||
testCompile("com.android.tools.build:gradle:1.1.0")
|
||||
testCompile(commonDep("junit:junit"))
|
||||
packedJars(project(":kotlin-annotation-processing")) { isTransitive = false }
|
||||
runtime(projectRuntimeJar(":kotlin-compiler-embeddable"))
|
||||
}
|
||||
@@ -32,11 +26,11 @@ jar.apply {
|
||||
}
|
||||
|
||||
runtimeJar(rewriteDepsToShadedCompiler(
|
||||
task<ShadowJar>("shadowJar") {
|
||||
from(packedJars)
|
||||
from(the<JavaPluginConvention>().sourceSets.getByName("main").output)
|
||||
}
|
||||
task<ShadowJar>("shadowJar") {
|
||||
from(packedJars)
|
||||
}
|
||||
))
|
||||
|
||||
sourcesJar()
|
||||
javadocJar()
|
||||
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
sealed class AnnotatedElement(val classFqName: String) {
|
||||
class Class(classFqName: String) : AnnotatedElement(classFqName) {
|
||||
override fun equals(other: Any?) = other is Class && classFqName == other.classFqName
|
||||
|
||||
override fun hashCode() = classFqName.hashCode()
|
||||
}
|
||||
|
||||
class Method(classFqName: String, val methodName: String) : AnnotatedElement(classFqName) {
|
||||
override fun equals(other: Any?) = other is Method && methodName == other.methodName && classFqName == other.classFqName
|
||||
|
||||
override fun hashCode() = 31 * classFqName.hashCode() + methodName.hashCode()
|
||||
}
|
||||
|
||||
class Constructor(classFqName: String) : AnnotatedElement(classFqName) {
|
||||
companion object {
|
||||
const val METHOD_NAME = "<init>"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = other is Constructor && classFqName == other.classFqName
|
||||
|
||||
override fun hashCode() = 31 * classFqName.hashCode() + METHOD_NAME.hashCode()
|
||||
}
|
||||
|
||||
class Field(classFqName: String, val fieldName: String) : AnnotatedElement(classFqName) {
|
||||
override fun equals(other: Any?) = other is Field && fieldName == other.fieldName && classFqName == other.classFqName
|
||||
|
||||
override fun hashCode() = 31 * classFqName.hashCode() + fieldName.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
fun AnnotationWriter.writeAnnotatedElement(annotation: String, element: AnnotatedElement) {
|
||||
when (element) {
|
||||
is AnnotatedElement.Class -> {
|
||||
writeAnnotatedClass(annotation, element.classFqName)
|
||||
}
|
||||
is AnnotatedElement.Constructor -> {
|
||||
writeAnnotatedMethod(annotation, element.classFqName, AnnotatedElement.Constructor.METHOD_NAME)
|
||||
}
|
||||
is AnnotatedElement.Method -> {
|
||||
writeAnnotatedMethod(annotation, element.classFqName, element.methodName)
|
||||
}
|
||||
is AnnotatedElement.Field -> {
|
||||
writeAnnotatedField(annotation, element.classFqName, element.fieldName)
|
||||
}
|
||||
}
|
||||
}
|
||||
-144
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import java.io.File
|
||||
import javax.annotation.processing.*
|
||||
import javax.lang.model.SourceVersion
|
||||
import javax.lang.model.element.AnnotationMirror
|
||||
import javax.lang.model.element.Element
|
||||
import javax.lang.model.element.ExecutableElement
|
||||
import javax.lang.model.element.TypeElement
|
||||
import javax.tools.Diagnostic
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
class AnnotationProcessorStub : AbstractProcessor() {
|
||||
override fun process(annotations: Set<TypeElement>?, roundEnv: RoundEnvironment?) = true
|
||||
}
|
||||
|
||||
abstract class AnnotationProcessorWrapper(
|
||||
private val processorFqName: String,
|
||||
private val taskQualifier: String
|
||||
) : Processor {
|
||||
|
||||
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 {
|
||||
try {
|
||||
val instance = Class.forName(processorFqName).newInstance() as? Processor
|
||||
instance ?: throw IllegalArgumentException("Instance has a wrong type: $processorFqName")
|
||||
}
|
||||
catch (e: Exception) {
|
||||
AnnotationProcessorStub()
|
||||
}
|
||||
}
|
||||
|
||||
private var processingEnv: ProcessingEnvironment by Delegates.notNull()
|
||||
|
||||
private var kotlinAnnotationsProvider: KotlinAnnotationProvider by Delegates.notNull()
|
||||
|
||||
private var roundCounter = 0
|
||||
|
||||
private var handledAnnotationTypes: Set<String> = emptySet()
|
||||
|
||||
override fun getCompletions(
|
||||
element: Element?,
|
||||
annotation: AnnotationMirror?,
|
||||
member: ExecutableElement?,
|
||||
userText: String?
|
||||
): MutableIterable<Completion> {
|
||||
return processor.getCompletions(element, annotation, member, userText)
|
||||
}
|
||||
|
||||
override fun init(processingEnv: ProcessingEnvironment) {
|
||||
this.processingEnv = processingEnv
|
||||
|
||||
if (processor is AnnotationProcessorStub) {
|
||||
processingEnv.err("Can't instantiate processor $processorFqName")
|
||||
return
|
||||
}
|
||||
|
||||
val annotationsFilePath = processingEnv.options[KAPT_ANNOTATION_OPTION]
|
||||
val annotationsFile = if (annotationsFilePath != null) File(annotationsFilePath) else null
|
||||
kotlinAnnotationsProvider = if (annotationsFile != null && annotationsFile.exists()) {
|
||||
KotlinAnnotationProvider(annotationsFile)
|
||||
}
|
||||
else {
|
||||
KotlinAnnotationProvider()
|
||||
}
|
||||
|
||||
processor.init(processingEnv)
|
||||
|
||||
handledAnnotationTypes = this.supportedAnnotationTypes
|
||||
}
|
||||
|
||||
override fun getSupportedAnnotationTypes(): MutableSet<String> {
|
||||
val supportedAnnotations = processor.supportedAnnotationTypes.toMutableSet()
|
||||
supportedAnnotations.add(KAPT_SPECIAL_ANNOTATION)
|
||||
return supportedAnnotations
|
||||
}
|
||||
|
||||
override fun getSupportedSourceVersion(): SourceVersion? {
|
||||
return processor.supportedSourceVersion
|
||||
}
|
||||
|
||||
override fun process(annotations: Set<TypeElement>?, roundEnv: RoundEnvironment): Boolean {
|
||||
roundCounter += 1
|
||||
|
||||
val roundEnvironmentWrapper = RoundEnvironmentWrapper(
|
||||
processingEnv, roundEnv, roundCounter, kotlinAnnotationsProvider)
|
||||
|
||||
val wrappedAnnotations = annotations?.toMutableSet() ?: hashSetOf<TypeElement>()
|
||||
val existingFqNames = wrappedAnnotations.mapTo(hashSetOf<String>()) { it.qualifiedName.toString() }
|
||||
|
||||
if (roundCounter == 1) {
|
||||
for (annotationFqName in kotlinAnnotationsProvider.annotatedKotlinElements.keys) {
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
processor.process(wrappedAnnotations, roundEnvironmentWrapper)
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getSupportedOptions(): MutableSet<String> {
|
||||
val supportedOptions = processor.supportedOptions.toHashSet()
|
||||
supportedOptions.add(KAPT_ANNOTATION_OPTION)
|
||||
supportedOptions.add(KAPT_KOTLIN_GENERATED_OPTION)
|
||||
return supportedOptions
|
||||
}
|
||||
|
||||
private fun ProcessingEnvironment.err(message: String) {
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, message)
|
||||
}
|
||||
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import java.io.Writer
|
||||
import org.jetbrains.kotlin.annotation.CompactNotationType as Notation
|
||||
|
||||
abstract class AnnotationWriter(private val writer: Writer) {
|
||||
companion object {
|
||||
private val LINE_SEP = System.getProperty("line.separator")
|
||||
}
|
||||
|
||||
abstract fun writeClassDeclaration(classFqName: String)
|
||||
abstract fun writeAnnotatedClass(annotationName: String, classFqName: String)
|
||||
abstract fun writeAnnotatedMethod(annotationName: String, classFqName: String, methodName: String)
|
||||
abstract fun writeAnnotatedField(annotationName: String, classFqName: String, fieldName: String)
|
||||
|
||||
protected fun writeLine(vararg parts: String?) {
|
||||
var i = 0
|
||||
for (part in parts) {
|
||||
if (part == null) continue
|
||||
if (i > 0) {
|
||||
writer.write(" ")
|
||||
}
|
||||
writer.write(part)
|
||||
i++
|
||||
}
|
||||
writer.write(LINE_SEP)
|
||||
}
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import java.io.Writer
|
||||
import org.jetbrains.kotlin.annotation.CompactNotationType as Notation
|
||||
|
||||
class CompactAnnotationWriter(writer: Writer) : AnnotationWriter(writer) {
|
||||
private val annotationsShortener = NameShortener(Notation.SHORTENED_ANNOTATION)
|
||||
private val packageShortener = NameShortener(Notation.SHORTENED_PACKAGE_NAME)
|
||||
|
||||
override fun writeClassDeclaration(classFqName: String) {
|
||||
writeLine(Notation.CLASS_DECLARATION, getShortenedClassName(classFqName))
|
||||
}
|
||||
|
||||
override fun writeAnnotatedClass(annotationName: String, classFqName: String) {
|
||||
writeAnnotated(Notation.ANNOTATED_CLASS, annotationName, classFqName)
|
||||
}
|
||||
|
||||
override fun writeAnnotatedMethod(annotationName: String, classFqName: String, methodName: String) {
|
||||
writeAnnotated(Notation.ANNOTATED_METHOD, annotationName, classFqName, methodName)
|
||||
}
|
||||
|
||||
override fun writeAnnotatedField(annotationName: String, classFqName: String, fieldName: String) {
|
||||
writeAnnotated(Notation.ANNOTATED_FIELD, annotationName, classFqName, fieldName)
|
||||
}
|
||||
|
||||
private fun writeAnnotated(type: String, annotationName: String, className: String, memberName: String? = null) {
|
||||
writeLine(type, annotationsShortener[annotationName].toString(), getShortenedClassName(className), memberName)
|
||||
}
|
||||
|
||||
private fun getShortenedClassName(fqName: String): String {
|
||||
val lastDotIndex = fqName.lastIndexOf('.')
|
||||
if (lastDotIndex == -1) return fqName
|
||||
|
||||
val packageName = fqName.substring(0, lastDotIndex)
|
||||
val simpleName = fqName.substring(lastDotIndex + 1)
|
||||
|
||||
return "${packageShortener[packageName]}/$simpleName"
|
||||
}
|
||||
|
||||
private inner class NameShortener(private val type: String) {
|
||||
private val names = hashMapOf<String, Int>()
|
||||
|
||||
operator fun get(name: String): Int =
|
||||
names.getOrPut(name) {
|
||||
val id = names.size
|
||||
writeLine(type, name, "$id")
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
object CompactNotationType {
|
||||
const val ANNOTATED_CLASS = "c"
|
||||
const val ANNOTATED_METHOD = "m"
|
||||
const val ANNOTATED_FIELD = "f"
|
||||
|
||||
const val SHORTENED_ANNOTATION = "a"
|
||||
const val SHORTENED_PACKAGE_NAME = "p"
|
||||
|
||||
const val CLASS_DECLARATION = "d"
|
||||
}
|
||||
-120
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import java.io.File
|
||||
import java.io.Reader
|
||||
import java.io.StringReader
|
||||
import org.jetbrains.kotlin.annotation.CompactNotationType as Notation
|
||||
|
||||
open class KotlinAnnotationProvider(annotationsReader: Reader) {
|
||||
constructor(annotationsFile: File) : this(annotationsFile.reader().buffered())
|
||||
constructor() : this(StringReader(""))
|
||||
|
||||
protected val kotlinClassesInternal = linkedSetOf<String>()
|
||||
protected val annotatedKotlinElementsInternal = linkedMapOf<String, MutableSet<AnnotatedElement>>()
|
||||
|
||||
init {
|
||||
readAnnotations(annotationsReader)
|
||||
}
|
||||
|
||||
val annotatedKotlinElements: Map<String, Set<AnnotatedElement>>
|
||||
get() = annotatedKotlinElementsInternal
|
||||
|
||||
val kotlinClasses: Set<String>
|
||||
get() = kotlinClassesInternal
|
||||
|
||||
val supportInheritedAnnotations: Boolean
|
||||
get() = kotlinClassesInternal.isNotEmpty()
|
||||
|
||||
protected fun readAnnotations(annotationsReader: Reader) {
|
||||
fun handleShortenedName(cache: MutableMap<String, String>, lineParts: List<String>) {
|
||||
val name = lineParts[1]
|
||||
val id = lineParts[2]
|
||||
cache.put(id, name)
|
||||
}
|
||||
|
||||
val shortenedAnnotationCache = linkedMapOf<String, String>()
|
||||
val shortenedPackageNameCache = linkedMapOf<String, String>()
|
||||
|
||||
fun expandAnnotation(s: String) = shortenedAnnotationCache.getOrElse(s) { s }
|
||||
|
||||
fun expandClassName(s: String): String {
|
||||
val id = s.substringBefore('/', "")
|
||||
if (id.isEmpty()) return s
|
||||
val shortenedValue = shortenedPackageNameCache.get(id) ?:
|
||||
throw RuntimeException("Value for $id couldn't be found in shrink cache")
|
||||
|
||||
return shortenedValue + '.' + s.substring(id.length + 1)
|
||||
}
|
||||
|
||||
annotationsReader.useLines { lines ->
|
||||
for (line in lines) {
|
||||
if (line.isEmpty()) continue
|
||||
val lineParts = line.split(' ')
|
||||
|
||||
val type = lineParts[0]
|
||||
when (type) {
|
||||
Notation.SHORTENED_ANNOTATION -> handleShortenedName(shortenedAnnotationCache, lineParts)
|
||||
Notation.SHORTENED_PACKAGE_NAME -> handleShortenedName(shortenedPackageNameCache, lineParts)
|
||||
Notation.CLASS_DECLARATION -> {
|
||||
val classFqName = expandClassName(lineParts[1]).replace('$', '.')
|
||||
kotlinClassesInternal.add(classFqName)
|
||||
}
|
||||
|
||||
Notation.ANNOTATED_CLASS, Notation.ANNOTATED_FIELD, Notation.ANNOTATED_METHOD -> {
|
||||
val annotationName = expandAnnotation(lineParts[1])
|
||||
val classFqName = expandClassName(lineParts[2]).replace('$', '.')
|
||||
val elementName = if (lineParts.size == 4) lineParts[3] else null
|
||||
|
||||
val set = annotatedKotlinElementsInternal.getOrPut(annotationName) { linkedSetOf() }
|
||||
set.add(when (type) {
|
||||
Notation.ANNOTATED_CLASS -> AnnotatedElement.Class(classFqName)
|
||||
Notation.ANNOTATED_FIELD -> {
|
||||
val name = elementName ?: throw AssertionError("Name for field must be provided")
|
||||
AnnotatedElement.Field(classFqName, name)
|
||||
}
|
||||
Notation.ANNOTATED_METHOD -> {
|
||||
val name = elementName ?: throw AssertionError("Name for method must be provided")
|
||||
|
||||
if (AnnotatedElement.Constructor.METHOD_NAME == name)
|
||||
AnnotatedElement.Constructor(classFqName)
|
||||
else
|
||||
AnnotatedElement.Method(classFqName, name)
|
||||
}
|
||||
else -> throw AssertionError("Unknown type: $type")
|
||||
})
|
||||
|
||||
}
|
||||
else -> throw AssertionError("Unknown type: $type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun writeAnnotations(writer: AnnotationWriter) {
|
||||
for ((annotation, elements) in annotatedKotlinElements) {
|
||||
for (element in elements) {
|
||||
writer.writeAnnotatedElement(annotation, element)
|
||||
}
|
||||
}
|
||||
|
||||
for (className in kotlinClasses) {
|
||||
writer.writeClassDeclaration(className)
|
||||
}
|
||||
}
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import java.io.File
|
||||
import java.io.StringReader
|
||||
import org.jetbrains.kotlin.annotation.CompactNotationType as Notation
|
||||
|
||||
class MutableKotlinAnnotationProvider : KotlinAnnotationProvider(StringReader("")) {
|
||||
fun addAnnotationsFrom(file: File) {
|
||||
file.bufferedReader().use { readAnnotations(it) }
|
||||
}
|
||||
|
||||
fun removeClasses(classesFqNames: Set<String>) {
|
||||
kotlinClassesInternal.removeAll(classesFqNames)
|
||||
|
||||
for ((annotation, elements) in annotatedKotlinElementsInternal) {
|
||||
elements.removeAll { it.classFqName in classesFqNames }
|
||||
}
|
||||
}
|
||||
}
|
||||
-102
@@ -1,102 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import java.lang.annotation.Inherited
|
||||
import javax.annotation.processing.ProcessingEnvironment
|
||||
import javax.annotation.processing.RoundEnvironment
|
||||
import javax.lang.model.element.Element
|
||||
import javax.lang.model.element.ElementKind
|
||||
import javax.lang.model.element.TypeElement
|
||||
import javax.lang.model.type.NoType
|
||||
|
||||
internal class RoundEnvironmentWrapper(
|
||||
val processingEnv: ProcessingEnvironment,
|
||||
val parent: RoundEnvironment,
|
||||
val roundNumber: Int,
|
||||
val kotlinAnnotationsProvider: KotlinAnnotationProvider
|
||||
) : RoundEnvironment {
|
||||
|
||||
override fun getRootElements(): MutableSet<out Element>? {
|
||||
return parent.rootElements
|
||||
}
|
||||
|
||||
override fun getElementsAnnotatedWith(a: TypeElement): MutableSet<out Element>? {
|
||||
val elements = parent.getElementsAnnotatedWith(a).toHashSet()
|
||||
elements.addAll(resolveKotlinElements(a.qualifiedName.toString()))
|
||||
return elements
|
||||
}
|
||||
|
||||
override fun getElementsAnnotatedWith(a: Class<out Annotation>): MutableSet<out Element>? {
|
||||
val elements = parent.getElementsAnnotatedWith(a).toHashSet()
|
||||
elements.addAll(resolveKotlinElements(a.name))
|
||||
return elements
|
||||
}
|
||||
|
||||
override fun processingOver() = parent.processingOver()
|
||||
|
||||
override fun errorRaised() = parent.errorRaised()
|
||||
|
||||
private fun TypeElement.filterEnclosedElements(kind: ElementKind, name: String): List<Element> {
|
||||
return enclosedElements.filter { it.kind == kind && it.simpleName.toString() == name }
|
||||
}
|
||||
|
||||
private fun TypeElement.filterEnclosedElements(kind: ElementKind): List<Element> {
|
||||
return enclosedElements.filter { it.kind == kind }
|
||||
}
|
||||
|
||||
private fun Element.hasAnnotation(annotationFqName: String): Boolean {
|
||||
return annotationMirrors.any { annotationFqName == it.annotationType.asElement().toString() }
|
||||
}
|
||||
|
||||
private fun TypeElement.hasInheritedAnnotation(annotationFqName: String): Boolean {
|
||||
if (hasAnnotation(annotationFqName)) return true
|
||||
|
||||
val superclassMirror = superclass
|
||||
if (superclassMirror is NoType) return false
|
||||
|
||||
val superClass = processingEnv.typeUtils.asElement(superclassMirror)
|
||||
if (superClass !is TypeElement) return false
|
||||
|
||||
return superClass.hasInheritedAnnotation(annotationFqName)
|
||||
}
|
||||
|
||||
private fun resolveKotlinElements(annotationFqName: String): Set<Element> {
|
||||
if (roundNumber > 1) return setOf()
|
||||
|
||||
val descriptors = kotlinAnnotationsProvider.annotatedKotlinElements.get(annotationFqName) ?: setOf()
|
||||
val descriptorsWithKotlin = descriptors.fold(hashSetOf<Element>()) { set, descriptor ->
|
||||
val clazz = processingEnv.elementUtils.getTypeElement(descriptor.classFqName) ?: return@fold set
|
||||
when (descriptor) {
|
||||
is AnnotatedElement.Class -> set.add(clazz)
|
||||
is AnnotatedElement.Constructor -> {
|
||||
set.addAll(clazz.filterEnclosedElements(ElementKind.CONSTRUCTOR)
|
||||
.filter { it.hasAnnotation(annotationFqName) })
|
||||
}
|
||||
is AnnotatedElement.Field -> {
|
||||
set.addAll(clazz.filterEnclosedElements(ElementKind.FIELD, descriptor.fieldName)
|
||||
.filter { it.hasAnnotation(annotationFqName) })
|
||||
}
|
||||
is AnnotatedElement.Method -> {
|
||||
set.addAll(clazz.filterEnclosedElements(ElementKind.METHOD, descriptor.methodName)
|
||||
.filter { it.hasAnnotation(annotationFqName) })
|
||||
}
|
||||
}
|
||||
set
|
||||
}
|
||||
|
||||
if (kotlinAnnotationsProvider.supportInheritedAnnotations) {
|
||||
val isInherited = processingEnv.elementUtils.getTypeElement(annotationFqName)
|
||||
?.hasAnnotation(Inherited::class.java.canonicalName) ?: false
|
||||
|
||||
if (isInherited) {
|
||||
kotlinAnnotationsProvider.kotlinClasses.forEach { classFqName ->
|
||||
val clazz = processingEnv.elementUtils.getTypeElement(classFqName) ?: return@forEach
|
||||
if (clazz.hasInheritedAnnotation(annotationFqName)) {
|
||||
descriptorsWithKotlin.add(clazz)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return descriptorsWithKotlin
|
||||
}
|
||||
}
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
open class AnnotationListParseTest {
|
||||
companion object {
|
||||
const val ANNOTATIONS_FILE_NAME = "annotations.txt"
|
||||
const val PARSED_FILE_NAME = "parsed.txt"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAnnotatedGettersSetters() = doTest("annotatedGettersSetters")
|
||||
|
||||
@Test
|
||||
fun testAnnotationInSameFile() = doTest("annotationInSameFile")
|
||||
|
||||
@Test
|
||||
fun testAnonymousClasses() = doTest("anonymousClasses")
|
||||
|
||||
@Test
|
||||
fun testClassAnnotations() = doTest("classAnnotations")
|
||||
|
||||
@Test
|
||||
fun testConstructors() = doTest("constructors")
|
||||
|
||||
@Test
|
||||
fun testDefaultPackage() = doTest("defaultPackage")
|
||||
|
||||
@Test
|
||||
fun testFieldAnnotations() = doTest("fieldAnnotations")
|
||||
|
||||
@Test
|
||||
fun testLocalClasses() = doTest("localClasses")
|
||||
|
||||
@Test
|
||||
fun testMethodAnnotations() = doTest("methodAnnotations")
|
||||
|
||||
@Test
|
||||
fun testNestedClasses() = doTest("nestedClasses")
|
||||
|
||||
@Test
|
||||
fun testSimple() = doTest("simple")
|
||||
|
||||
@Test
|
||||
fun testDeclarations() = doTest("classDeclarations")
|
||||
|
||||
|
||||
private val resourcesRootFile = File("src/test/resources/parse")
|
||||
|
||||
private fun doTest(testName: String) {
|
||||
doTest(testDir = File(resourcesRootFile, testName))
|
||||
}
|
||||
|
||||
protected open fun doTest(testDir: File) {
|
||||
val annotationsFile = File(testDir, ANNOTATIONS_FILE_NAME)
|
||||
val expectedFile = File(testDir, PARSED_FILE_NAME)
|
||||
|
||||
assertTrue(annotationsFile.absolutePath + " does not exist.", annotationsFile.exists())
|
||||
|
||||
val annotationProvider = KotlinAnnotationProvider(annotationsFile)
|
||||
val parsedAnnotations = annotationProvider.annotatedKotlinElements
|
||||
|
||||
val actualAnnotations = StringBuilder()
|
||||
parsedAnnotations.forEach {
|
||||
for (element in it.value) {
|
||||
actualAnnotations.append(it.key).append(' ').append(element.classFqName)
|
||||
when (element) {
|
||||
is AnnotatedElement.Method ->
|
||||
actualAnnotations.append(' ').append(element.methodName)
|
||||
is AnnotatedElement.Field ->
|
||||
actualAnnotations.append(' ').append(element.fieldName)
|
||||
is AnnotatedElement.Constructor ->
|
||||
actualAnnotations.append(" ${AnnotatedElement.Constructor.METHOD_NAME}")
|
||||
is AnnotatedElement.Class -> {}
|
||||
}
|
||||
actualAnnotations.append('\n')
|
||||
}
|
||||
}
|
||||
|
||||
val actualAnnotationsSorted = actualAnnotations.toString().lines().filter { it.isNotEmpty() }.sorted()
|
||||
val classDeclarationsSorted = annotationProvider.kotlinClasses.sorted()
|
||||
|
||||
val fileContents = (actualAnnotationsSorted + classDeclarationsSorted).joinToString("\n")
|
||||
assertEqualsToFile(expectedFile, fileContents)
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import com.google.common.io.Files
|
||||
import java.io.File
|
||||
|
||||
class AnnotationSerializationTest : AnnotationListParseTest() {
|
||||
// after reading and serializing annotations file should not change the result of AnnotationListParseTest
|
||||
override fun doTest(testDir: File) {
|
||||
val workingDir = Files.createTempDir()
|
||||
testDir.copyRecursively(workingDir)
|
||||
|
||||
val annotationsFile = File(workingDir, ANNOTATIONS_FILE_NAME)
|
||||
val annotationProvider = KotlinAnnotationProvider(annotationsFile)
|
||||
annotationsFile.delete()
|
||||
|
||||
annotationsFile.bufferedWriter().use { writer ->
|
||||
val annotationWriter = CompactAnnotationWriter(writer)
|
||||
annotationProvider.writeAnnotations(annotationWriter)
|
||||
}
|
||||
|
||||
super.doTest(workingDir)
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.io.StringWriter
|
||||
|
||||
class MutableAnnotationProviderTest {
|
||||
private val resourcesRootFile = File("src/test/resources/mutate")
|
||||
|
||||
@Test
|
||||
fun testRemoveClass() {
|
||||
val testDir = File(resourcesRootFile, "removeClass")
|
||||
val annotationsFile = File(testDir, "annotations.txt")
|
||||
val annotationsFileUpdated = File(testDir, "annotations-updated.txt")
|
||||
|
||||
val content = mutateAnnotationsFiles {
|
||||
addAnnotationsFrom(annotationsFile)
|
||||
removeClasses(setOf("foo.A"))
|
||||
}
|
||||
|
||||
assertEqualsToFile(annotationsFileUpdated, content)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMergeFiles() {
|
||||
val testDir = File(resourcesRootFile, "mergeFiles")
|
||||
val annotationsAFile = File(testDir, "annotationsA.txt")
|
||||
val annotationsBFile = File(testDir, "annotationsB.txt")
|
||||
val annotationsMergedFile = File(testDir, "annotations-merged.txt")
|
||||
|
||||
val content = mutateAnnotationsFiles {
|
||||
addAnnotationsFrom(annotationsAFile)
|
||||
addAnnotationsFrom(annotationsBFile)
|
||||
}
|
||||
|
||||
assertEqualsToFile(annotationsMergedFile, content)
|
||||
}
|
||||
|
||||
private fun mutateAnnotationsFiles(fn: MutableKotlinAnnotationProvider.() -> Unit): String {
|
||||
val annotationProvider = MutableKotlinAnnotationProvider()
|
||||
annotationProvider.fn()
|
||||
|
||||
val writer = StringWriter()
|
||||
annotationProvider.writeAnnotations(CompactAnnotationWriter(writer))
|
||||
return writer.toString()
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
|
||||
fun assertEqualsToFile(expectedFile: File, actual: String) {
|
||||
val lineSeparator = System.getProperty("line.separator")
|
||||
val actualText = actual.replace(lineSeparator, "\n").trim('\n', ' ', '\t')
|
||||
|
||||
if (!expectedFile.exists()) {
|
||||
expectedFile.writeText(actualText.replace("\n", lineSeparator))
|
||||
Assert.fail("Expected data file did not exist. Generating: " + expectedFile)
|
||||
}
|
||||
|
||||
val expectedText = expectedFile.readText().replace(lineSeparator, "\n")
|
||||
|
||||
Assert.assertEquals(expectedText, actualText)
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
a annotations.Ann 0
|
||||
p foo 0
|
||||
c 0 0/A
|
||||
m 0 0/A valA$annotations
|
||||
m 0 0/A funA
|
||||
p bar 1
|
||||
c 0 1/B
|
||||
m 0 1/B valB$annotations
|
||||
m 0 1/B funB
|
||||
a java.lang.annotation.Retention 1
|
||||
p annotations 2
|
||||
c 1 2/Ann
|
||||
d 0/A
|
||||
d 2/Ann
|
||||
d 1/B
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
p foo 0
|
||||
d 0/A
|
||||
a annotations.Ann 0
|
||||
c 0 0/A
|
||||
m 0 0/A valA$annotations
|
||||
m 0 0/A funA
|
||||
p annotations 1
|
||||
d 1/Ann
|
||||
a java.lang.annotation.Retention 1
|
||||
c 1 1/Ann
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
p bar 0
|
||||
d 0/B
|
||||
a annotations.Ann 0
|
||||
c 0 0/B
|
||||
m 0 0/B valB$annotations
|
||||
m 0 0/B funB
|
||||
p annotations 1
|
||||
d 1/Ann
|
||||
a java.lang.annotation.Retention 1
|
||||
c 1 1/Ann
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
a annotations.Ann 0
|
||||
p bar 0
|
||||
c 0 0/B
|
||||
m 0 0/B valB$annotations
|
||||
m 0 0/B funB
|
||||
a java.lang.annotation.Retention 1
|
||||
p annotations 1
|
||||
c 1 1/Ann
|
||||
d 0/B
|
||||
d 1/Ann
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
p bar 0
|
||||
d 0/B
|
||||
a annotations.Ann 0
|
||||
c 0 0/B
|
||||
m 0 0/B valB$annotations
|
||||
m 0 0/B funB
|
||||
p foo 1
|
||||
d 1/A
|
||||
c 0 1/A
|
||||
m 0 1/A valA$annotations
|
||||
m 0 1/A funA
|
||||
p annotations 2
|
||||
d 2/Ann
|
||||
a java.lang.annotation.Retention 1
|
||||
c 1 2/Ann
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
a kotlin.data 0
|
||||
p org.test 0
|
||||
c 0 0/SomeClass
|
||||
a java.lang.Deprecated 1
|
||||
m 1 0/SomeClass getImmutableProperty
|
||||
a org.jetbrains.annotations.NotNull 2
|
||||
f 2 0/SomeClass mutableProperty
|
||||
m 1 0/SomeClass getMutableProperty
|
||||
m 2 0/SomeClass getMutableProperty
|
||||
m 1 0/SomeClass setMutableProperty
|
||||
m 2 0/SomeClass copy
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
java.lang.Deprecated org.test.SomeClass getImmutableProperty
|
||||
java.lang.Deprecated org.test.SomeClass getMutableProperty
|
||||
java.lang.Deprecated org.test.SomeClass setMutableProperty
|
||||
kotlin.data org.test.SomeClass
|
||||
org.jetbrains.annotations.NotNull org.test.SomeClass copy
|
||||
org.jetbrains.annotations.NotNull org.test.SomeClass getMutableProperty
|
||||
org.jetbrains.annotations.NotNull org.test.SomeClass mutableProperty
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
a org.test.SomeAnnotation 0
|
||||
p org.test 0
|
||||
c 0 0/SomeClass
|
||||
m 0 0/SomeClass annotatedFunction
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
org.test.SomeAnnotation org.test.SomeClass
|
||||
org.test.SomeAnnotation org.test.SomeClass annotatedFunction
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
a java.lang.Deprecated 0
|
||||
p org.test 0
|
||||
f 0 0/SomeClass$a$1 property
|
||||
-1
@@ -1 +0,0 @@
|
||||
java.lang.Deprecated org.test.SomeClass.a.1 property
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
a javax.inject.Named 0
|
||||
p org.test 0
|
||||
c 0 0/SomeClass
|
||||
c 0 0/SomeObject
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
javax.inject.Named org.test.SomeClass
|
||||
javax.inject.Named org.test.SomeObject
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
p example 0
|
||||
d 0/TestClass
|
||||
a example.ExampleAnnotation 0
|
||||
c 0 0/TestClass
|
||||
d 0/AncestorClass
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
example.ExampleAnnotation example.TestClass
|
||||
example.AncestorClass
|
||||
example.TestClass
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
a java.lang.Deprecated 0
|
||||
p org.test 0
|
||||
m 0 0/SomeClass <init>
|
||||
m 0 0/SomeClass <init>
|
||||
-1
@@ -1 +0,0 @@
|
||||
java.lang.Deprecated org.test.SomeClass <init>
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
a javax.inject.Named 0
|
||||
c 0 SomeClass
|
||||
a javax.inject.Inject 1
|
||||
f 1 SomeClass annotatedProperty
|
||||
a org.jetbrains.annotations.Nullable 2
|
||||
f 2 SomeClass annotatedProperty
|
||||
m 2 SomeClass getAnnotatedProperty
|
||||
m 1 SomeClass annotatedFunction
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
javax.inject.Inject SomeClass annotatedFunction
|
||||
javax.inject.Inject SomeClass annotatedProperty
|
||||
javax.inject.Named SomeClass
|
||||
org.jetbrains.annotations.Nullable SomeClass annotatedProperty
|
||||
org.jetbrains.annotations.Nullable SomeClass getAnnotatedProperty
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
a javax.inject.Inject 0
|
||||
p org.test 0
|
||||
f 0 0/SomeClass annotatedVal
|
||||
a org.jetbrains.annotations.Nullable 1
|
||||
f 1 0/SomeClass annotatedVal
|
||||
m 1 0/SomeClass getAnnotatedVal
|
||||
f 0 0/SomeClass annotatedVar
|
||||
f 0 0/OtherClass annotatedVal
|
||||
f 0 0/OtherClass annotatedVar
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
javax.inject.Inject org.test.OtherClass annotatedVal
|
||||
javax.inject.Inject org.test.OtherClass annotatedVar
|
||||
javax.inject.Inject org.test.SomeClass annotatedVal
|
||||
javax.inject.Inject org.test.SomeClass annotatedVar
|
||||
org.jetbrains.annotations.Nullable org.test.SomeClass annotatedVal
|
||||
org.jetbrains.annotations.Nullable org.test.SomeClass getAnnotatedVal
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
a javax.inject.Named 0
|
||||
p org.test 0
|
||||
c 0 0/SomeClass$someFunction$LocalClass
|
||||
a javax.inject.Inject 1
|
||||
f 1 0/SomeClass$someFunction$LocalClass annotatedProperty
|
||||
a org.jetbrains.annotations.Nullable 2
|
||||
f 2 0/SomeClass$someFunction$LocalClass annotatedProperty
|
||||
m 2 0/SomeClass$someFunction$LocalClass getAnnotatedProperty
|
||||
m 1 0/SomeClass$someFunction$LocalClass annotatedFunction
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
javax.inject.Inject org.test.SomeClass.someFunction.LocalClass annotatedFunction
|
||||
javax.inject.Inject org.test.SomeClass.someFunction.LocalClass annotatedProperty
|
||||
javax.inject.Named org.test.SomeClass.someFunction.LocalClass
|
||||
org.jetbrains.annotations.Nullable org.test.SomeClass.someFunction.LocalClass annotatedProperty
|
||||
org.jetbrains.annotations.Nullable org.test.SomeClass.someFunction.LocalClass getAnnotatedProperty
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
a javax.inject.Inject 0
|
||||
p org.test 0
|
||||
m 0 0/SomeClass annotatedFunction
|
||||
m 0 0/OtherClass annotatedFunction
|
||||
a javax.inject.Named 1
|
||||
m 1 0/SomeClass$annotatedFunction$1 invoke
|
||||
m 1 0/OtherClass$annotatedFunction$1 invoke
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
javax.inject.Inject org.test.OtherClass annotatedFunction
|
||||
javax.inject.Inject org.test.SomeClass annotatedFunction
|
||||
javax.inject.Named org.test.OtherClass.annotatedFunction.1 invoke
|
||||
javax.inject.Named org.test.SomeClass.annotatedFunction.1 invoke
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
a javax.inject.Named 0
|
||||
p org.test 0
|
||||
c 0 0/SomeClass$Companion
|
||||
a org.jetbrains.annotations.NotNull 1
|
||||
m 1 0/SomeClass$Companion access$init$0
|
||||
c 0 0/SomeClass$SomeInnerObject
|
||||
c 0 0/SomeClass$InnerClass
|
||||
c 0 0/SomeClass$NestedClass
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
javax.inject.Named org.test.SomeClass.Companion
|
||||
javax.inject.Named org.test.SomeClass.InnerClass
|
||||
javax.inject.Named org.test.SomeClass.NestedClass
|
||||
javax.inject.Named org.test.SomeClass.SomeInnerObject
|
||||
org.jetbrains.annotations.NotNull org.test.SomeClass.Companion access$init$0
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
a javax.inject.Inject 0
|
||||
p org.test 0
|
||||
m 0 0/SomeClass annotatedFunction
|
||||
-1
@@ -1 +0,0 @@
|
||||
javax.inject.Inject org.test.SomeClass annotatedFunction
|
||||
Reference in New Issue
Block a user