Serialize KotlinAnnotationProvider
This commit is contained in:
+17
@@ -23,4 +23,21 @@ sealed class AnnotatedElementDescriptor(val classFqName: String) {
|
||||
|
||||
override fun hashCode() = 31 * classFqName.hashCode() + fieldName.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
fun AnnotationWriter.writeAnnotatedElement(annotation: String, element: AnnotatedElementDescriptor) {
|
||||
when (element) {
|
||||
is AnnotatedElementDescriptor.Class -> {
|
||||
writeAnnotatedClass(annotation, element.classFqName)
|
||||
}
|
||||
is AnnotatedElementDescriptor.Constructor -> {
|
||||
writeAnnotatedMethod(annotation, element.classFqName, AnnotatedElementDescriptor.Constructor.METHOD_NAME)
|
||||
}
|
||||
is AnnotatedElementDescriptor.Method -> {
|
||||
writeAnnotatedMethod(annotation, element.classFqName, element.methodName)
|
||||
}
|
||||
is AnnotatedElementDescriptor.Field -> {
|
||||
writeAnnotatedField(annotation, element.classFqName, element.fieldName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
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
@@ -0,0 +1,50 @@
|
||||
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
@@ -0,0 +1,12 @@
|
||||
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"
|
||||
}
|
||||
+22
-20
@@ -19,20 +19,10 @@ package org.jetbrains.kotlin.annotation
|
||||
import java.io.File
|
||||
import java.io.Reader
|
||||
import java.io.StringReader
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.annotation.CompactNotationType as Notation
|
||||
|
||||
class KotlinAnnotationProvider(annotationsReader: Reader) {
|
||||
|
||||
private companion object {
|
||||
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"
|
||||
}
|
||||
|
||||
constructor(annotationsFile: File) : this(annotationsFile.reader().buffered())
|
||||
constructor() : this(StringReader(""))
|
||||
|
||||
@@ -80,26 +70,26 @@ class KotlinAnnotationProvider(annotationsReader: Reader) {
|
||||
|
||||
val type = lineParts[0]
|
||||
when (type) {
|
||||
SHORTENED_ANNOTATION -> handleShortenedName(shortenedAnnotationCache, lineParts)
|
||||
SHORTENED_PACKAGE_NAME -> handleShortenedName(shortenedPackageNameCache, lineParts)
|
||||
CLASS_DECLARATION -> {
|
||||
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)
|
||||
}
|
||||
|
||||
ANNOTATED_CLASS, ANNOTATED_FIELD, ANNOTATED_METHOD -> {
|
||||
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) { hashSetOf() }
|
||||
val set = annotatedKotlinElementsInternal.getOrPut(annotationName) { HashSet() }
|
||||
set.add(when (type) {
|
||||
ANNOTATED_CLASS -> AnnotatedElementDescriptor.Class(classFqName)
|
||||
ANNOTATED_FIELD -> {
|
||||
Notation.ANNOTATED_CLASS -> AnnotatedElementDescriptor.Class(classFqName)
|
||||
Notation.ANNOTATED_FIELD -> {
|
||||
val name = elementName ?: throw AssertionError("Name for field must be provided")
|
||||
AnnotatedElementDescriptor.Field(classFqName, name)
|
||||
}
|
||||
ANNOTATED_METHOD -> {
|
||||
Notation.ANNOTATED_METHOD -> {
|
||||
val name = elementName ?: throw AssertionError("Name for method must be provided")
|
||||
|
||||
if (AnnotatedElementDescriptor.Constructor.METHOD_NAME == name)
|
||||
@@ -116,4 +106,16 @@ class KotlinAnnotationProvider(annotationsReader: Reader) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun writeAnnotations(writer: AnnotationWriter) {
|
||||
for ((annotation, elements) in annotatedKotlinElements) {
|
||||
for (element in elements) {
|
||||
writer.writeAnnotatedElement(annotation, element)
|
||||
}
|
||||
}
|
||||
|
||||
for (className in kotlinClasses) {
|
||||
writer.writeClassDeclaration(className)
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-5
@@ -1,12 +1,16 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import org.junit.Assert.*
|
||||
import java.io.IOException
|
||||
|
||||
public class AnnotationListParseTest {
|
||||
open class AnnotationListParseTest {
|
||||
companion object {
|
||||
const val ANNOTATIONS_FILE_NAME = "annotations.txt"
|
||||
const val PARSED_FILE_NAME = "parsed.txt"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAnnotatedGettersSetters() = doTest("annotatedGettersSetters")
|
||||
@@ -48,8 +52,12 @@ public class AnnotationListParseTest {
|
||||
private val resourcesRootFile = File("src/test/resources/parse")
|
||||
|
||||
private fun doTest(testName: String) {
|
||||
val annotationsFile = File(resourcesRootFile, "$testName/annotations.txt")
|
||||
val expectedFile = File(resourcesRootFile, "$testName/parsed.txt")
|
||||
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())
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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()
|
||||
|
||||
val writer = annotationsFile.bufferedWriter()
|
||||
try {
|
||||
val annotationWriter = CompactAnnotationWriter(writer)
|
||||
annotationProvider.writeAnnotations(annotationWriter)
|
||||
}
|
||||
finally {
|
||||
writer.close()
|
||||
}
|
||||
|
||||
super.doTest(workingDir)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user