Kapt: Remove annotation processor wrappers for kapt1 (it's obsolete now)

This commit is contained in:
Yan Zhulanow
2018-05-16 23:02:40 +03:00
parent a76bb80e4d
commit 58643ea99d
42 changed files with 5 additions and 935 deletions
@@ -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()
@@ -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)
}
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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
}
}
}
@@ -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"
}
@@ -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)
}
}
}
@@ -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 }
}
}
}
@@ -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
}
}
@@ -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)
}
}
@@ -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)
}
}
@@ -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()
}
}
@@ -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)
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,4 +0,0 @@
a org.test.SomeAnnotation 0
p org.test 0
c 0 0/SomeClass
m 0 0/SomeClass annotatedFunction
@@ -1,2 +0,0 @@
org.test.SomeAnnotation org.test.SomeClass
org.test.SomeAnnotation org.test.SomeClass annotatedFunction
@@ -1,3 +0,0 @@
a java.lang.Deprecated 0
p org.test 0
f 0 0/SomeClass$a$1 property
@@ -1 +0,0 @@
java.lang.Deprecated org.test.SomeClass.a.1 property
@@ -1,4 +0,0 @@
a javax.inject.Named 0
p org.test 0
c 0 0/SomeClass
c 0 0/SomeObject
@@ -1,2 +0,0 @@
javax.inject.Named org.test.SomeClass
javax.inject.Named org.test.SomeObject
@@ -1,5 +0,0 @@
p example 0
d 0/TestClass
a example.ExampleAnnotation 0
c 0 0/TestClass
d 0/AncestorClass
@@ -1,3 +0,0 @@
example.ExampleAnnotation example.TestClass
example.AncestorClass
example.TestClass
@@ -1,4 +0,0 @@
a java.lang.Deprecated 0
p org.test 0
m 0 0/SomeClass <init>
m 0 0/SomeClass <init>
@@ -1 +0,0 @@
java.lang.Deprecated org.test.SomeClass <init>
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -1,3 +0,0 @@
a javax.inject.Inject 0
p org.test 0
m 0 0/SomeClass annotatedFunction
@@ -1 +0,0 @@
javax.inject.Inject org.test.SomeClass annotatedFunction