Fix collecting source retention annotations
#KT-12187 fixed
This commit is contained in:
@@ -279,7 +279,7 @@ public abstract class AnnotationCodegen {
|
||||
ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
|
||||
assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
|
||||
RetentionPolicy rp = getRetentionPolicy(classifierDescriptor);
|
||||
if (rp == RetentionPolicy.SOURCE && typeMapper.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
|
||||
if (rp == RetentionPolicy.SOURCE && typeMapper.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,10 @@ public class CodegenTestUtil {
|
||||
/* useTypeTableInSerializer = */ false,
|
||||
configuration.get(JVMConfigurationKeys.INHERIT_MULTIFILE_PARTS, false)
|
||||
);
|
||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
|
||||
|
||||
if (analysisResult.getShouldGenerateCode()) {
|
||||
KotlinCodegenFacade.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION);
|
||||
}
|
||||
|
||||
// For JVM-specific errors
|
||||
AnalyzingUtils.throwExceptionOnErrors(state.getCollectedExtraJvmDiagnostics());
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package example
|
||||
|
||||
import java.lang.annotation.ElementType
|
||||
import java.lang.annotation.Inherited
|
||||
import java.lang.annotation.Target
|
||||
|
||||
@Inherited
|
||||
annotation public class ExampleAnnotation
|
||||
+22
-12
@@ -6,19 +6,31 @@ import javax.annotation.processing.RoundEnvironment
|
||||
import javax.lang.model.SourceVersion
|
||||
import javax.lang.model.element.ElementKind
|
||||
import javax.lang.model.element.TypeElement
|
||||
import javax.tools.Diagnostic
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public class ExampleAnnotationProcessor : AbstractProcessor() {
|
||||
class ExampleAnnotationProcessor : AbstractProcessor() {
|
||||
|
||||
private companion object {
|
||||
val ANNOTATION_FQ_NAME = ExampleAnnotation::class.java.canonicalName
|
||||
val ANNOTATION_TO_PREFIX = mapOf(ExampleAnnotation::class to "",
|
||||
ExampleSourceAnnotation::class to "SourceAnnotated",
|
||||
ExampleRuntimeAnnotation::class to "RuntimeAnnotated",
|
||||
ExampleBinaryAnnotation::class to "BinaryAnnotated")
|
||||
|
||||
val SUFFIX_OPTION = "suffix"
|
||||
val GENERATE_KOTLIN_CODE_OPTION = "generate.kotlin.code"
|
||||
val KAPT_KOTLIN_GENERATED_OPTION = "kapt.kotlin.generated"
|
||||
}
|
||||
|
||||
override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment): Boolean {
|
||||
val elements = roundEnv.getElementsAnnotatedWith(ExampleAnnotation::class.java)
|
||||
for ((annotation, prefix) in ANNOTATION_TO_PREFIX) {
|
||||
processAnnotation(roundEnv, annotation, prefix)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun <T : Annotation> processAnnotation(roundEnv: RoundEnvironment, annotationClass: KClass<T>, generatedFilePrefix: String) {
|
||||
val elements = roundEnv.getElementsAnnotatedWith(annotationClass.java)
|
||||
|
||||
val elementUtils = processingEnv.elementUtils
|
||||
val filer = processingEnv.filer
|
||||
@@ -30,28 +42,26 @@ public class ExampleAnnotationProcessor : AbstractProcessor() {
|
||||
|
||||
for (element in elements) {
|
||||
val packageName = elementUtils.getPackageOf(element).qualifiedName.toString()
|
||||
val simpleName = element.simpleName
|
||||
val className = simpleName.toString().capitalize() + generatedFileSuffix
|
||||
val simpleName = element.simpleName.toString()
|
||||
val generatedJavaClassName = generatedFilePrefix.capitalize() + simpleName.capitalize() + generatedFileSuffix
|
||||
|
||||
filer.createSourceFile(className).openWriter().use { with(it) {
|
||||
filer.createSourceFile(generatedJavaClassName).openWriter().use { with(it) {
|
||||
appendln("package $packageName;")
|
||||
appendln("public final class $className {}")
|
||||
appendln("public final class $generatedJavaClassName {}")
|
||||
}}
|
||||
|
||||
if (generateKotlinCode && kotlinGenerated != null && element.kind == ElementKind.CLASS) {
|
||||
File(kotlinGenerated, "$simpleName.kt").writer().buffered().use {
|
||||
it.appendln("package $packageName")
|
||||
it.appendln("fun $simpleName.customToString() = \"$simpleName: \" + toString()")
|
||||
it.appendln("fun $simpleName.customToString() = \"$generatedJavaClassName: \" + toString()")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
override fun getSupportedSourceVersion() = SourceVersion.RELEASE_6
|
||||
|
||||
override fun getSupportedAnnotationTypes() = setOf(ANNOTATION_FQ_NAME)
|
||||
override fun getSupportedAnnotationTypes() = ANNOTATION_TO_PREFIX.keys.map { it.java.canonicalName }.toSet()
|
||||
|
||||
override fun getSupportedOptions() = setOf(SUFFIX_OPTION)
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package example
|
||||
|
||||
import java.lang.annotation.Inherited
|
||||
|
||||
@Inherited
|
||||
annotation class ExampleAnnotation
|
||||
|
||||
@Inherited
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class ExampleSourceAnnotation
|
||||
|
||||
@Inherited
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class ExampleBinaryAnnotation
|
||||
|
||||
@Inherited
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class ExampleRuntimeAnnotation
|
||||
+6
@@ -26,6 +26,9 @@ class KaptIT: BaseGradleIT() {
|
||||
assertFileExists("build/generated/source/kapt/main/TestClassGenerated.java")
|
||||
assertFileExists("build/classes/main/example/TestClass.class")
|
||||
assertFileExists("build/classes/main/example/TestClassGenerated.class")
|
||||
assertNoSuchFile("build/classes/main/example/SourceAnnotatedTestClassGenerated.class")
|
||||
assertFileExists("build/classes/main/example/BinaryAnnotatedTestClassGenerated.class")
|
||||
assertFileExists("build/classes/main/example/RuntimeAnnotatedTestClassGenerated.class")
|
||||
}
|
||||
|
||||
project.build("build") {
|
||||
@@ -46,6 +49,9 @@ class KaptIT: BaseGradleIT() {
|
||||
assertFileExists("build/generated/source/kapt/main/TestClassGenerated.java")
|
||||
assertFileExists("build/classes/main/example/TestClass.class")
|
||||
assertFileExists("build/classes/main/example/TestClassGenerated.class")
|
||||
assertFileExists("build/classes/main/example/SourceAnnotatedTestClassGenerated.class")
|
||||
assertFileExists("build/classes/main/example/BinaryAnnotatedTestClassGenerated.class")
|
||||
assertFileExists("build/classes/main/example/RuntimeAnnotatedTestClassGenerated.class")
|
||||
}
|
||||
|
||||
project.build("build") {
|
||||
|
||||
+2
@@ -20,6 +20,8 @@ public class JavaClass {
|
||||
|
||||
public void test() {
|
||||
System.out.println(example.TestClassGenerated.class.getName());
|
||||
System.out.println(example.BinaryAnnotatedTestClassGenerated.class.getName());
|
||||
System.out.println(example.RuntimeAnnotatedTestClassGenerated.class.getName());
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -1,6 +1,9 @@
|
||||
package example
|
||||
|
||||
@example.ExampleAnnotation
|
||||
@example.ExampleSourceAnnotation
|
||||
@example.ExampleBinaryAnnotation
|
||||
@example.ExampleRuntimeAnnotation
|
||||
public class TestClass {
|
||||
|
||||
@example.ExampleAnnotation
|
||||
|
||||
+3
@@ -20,6 +20,9 @@ public class JavaClass {
|
||||
|
||||
public void test() {
|
||||
System.out.println(example.TestClassGenerated.class.getName());
|
||||
System.out.println(example.SourceAnnotatedTestClassGenerated.class.getName());
|
||||
System.out.println(example.BinaryAnnotatedTestClassGenerated.class.getName());
|
||||
System.out.println(example.RuntimeAnnotatedTestClassGenerated.class.getName());
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -1,6 +1,9 @@
|
||||
package example
|
||||
|
||||
@example.ExampleAnnotation
|
||||
@example.ExampleSourceAnnotation
|
||||
@example.ExampleBinaryAnnotation
|
||||
@example.ExampleRuntimeAnnotation
|
||||
public class TestClass {
|
||||
|
||||
@example.ExampleAnnotation
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface ClassAnnotation {}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
public @interface DefaultAnnotation {}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RuntimeAnnotation {}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SourceAnnotation {}
|
||||
plugins/annotation-collector/testData/collectToFile/retentionPoliciesJavaAnnotations/annotations.txt
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
a DefaultAnnotation 0
|
||||
c 0 DafaultUsage
|
||||
a ClassAnnotation 1
|
||||
c 1 ClassUsage
|
||||
a RuntimeAnnotation 2
|
||||
c 2 RuntimeUsage
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
@DefaultAnnotation
|
||||
class DafaultUsage
|
||||
|
||||
@SourceAnnotation
|
||||
class SourceUsage
|
||||
|
||||
@ClassAnnotation
|
||||
class ClassUsage
|
||||
|
||||
@RuntimeAnnotation
|
||||
class RuntimeUsage
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface ClassAnnotation {}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
public @interface DefaultAnnotation {}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface RuntimeAnnotation {}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SourceAnnotation {}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
a DefaultAnnotation 0
|
||||
c 0 DafaultUsage
|
||||
a SourceAnnotation 1
|
||||
c 1 SourceUsage
|
||||
a ClassAnnotation 2
|
||||
c 2 ClassUsage
|
||||
a RuntimeAnnotation 3
|
||||
c 3 RuntimeUsage
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
@DefaultAnnotation
|
||||
class DafaultUsage
|
||||
|
||||
@SourceAnnotation
|
||||
class SourceUsage
|
||||
|
||||
@ClassAnnotation
|
||||
class ClassUsage
|
||||
|
||||
@RuntimeAnnotation
|
||||
class RuntimeUsage
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
annotation class DefaultAnnotation
|
||||
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class SourceAnnotation
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class BinaryAnnotation
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class RuntimeAnnotation
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
a java.lang.annotation.Retention 0
|
||||
c 0 DefaultAnnotation
|
||||
a kotlin.annotation.Retention 1
|
||||
c 1 SourceAnnotation
|
||||
c 0 SourceAnnotation
|
||||
c 1 BinaryAnnotation
|
||||
c 0 BinaryAnnotation
|
||||
c 1 RuntimeAnnotation
|
||||
c 0 RuntimeAnnotation
|
||||
a DefaultAnnotation 2
|
||||
c 2 DafaultUsage
|
||||
a BinaryAnnotation 3
|
||||
c 3 BinaryUsage
|
||||
a RuntimeAnnotation 4
|
||||
c 4 RuntimeUsage
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
@DefaultAnnotation
|
||||
class DafaultUsage
|
||||
|
||||
@SourceAnnotation
|
||||
class SourceUsage
|
||||
|
||||
@BinaryAnnotation
|
||||
class BinaryUsage
|
||||
|
||||
@RuntimeAnnotation
|
||||
class RuntimeUsage
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
annotation class DefaultAnnotation
|
||||
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class SourceAnnotation
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class BinaryAnnotation
|
||||
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class RuntimeAnnotation
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
a java.lang.annotation.Retention 0
|
||||
c 0 DefaultAnnotation
|
||||
a kotlin.annotation.Retention 1
|
||||
c 1 SourceAnnotation
|
||||
c 0 SourceAnnotation
|
||||
c 1 BinaryAnnotation
|
||||
c 0 BinaryAnnotation
|
||||
c 1 RuntimeAnnotation
|
||||
c 0 RuntimeAnnotation
|
||||
a DefaultAnnotation 2
|
||||
c 2 DafaultUsage
|
||||
a SourceAnnotation 3
|
||||
c 3 SourceUsage
|
||||
a BinaryAnnotation 4
|
||||
c 4 BinaryUsage
|
||||
a RuntimeAnnotation 5
|
||||
c 5 RuntimeUsage
|
||||
plugins/annotation-collector/testData/collectToFile/retentionPoliciesKotlinAnnotationsStubs/usage.kt
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
@DefaultAnnotation
|
||||
class DafaultUsage
|
||||
|
||||
@SourceAnnotation
|
||||
class SourceUsage
|
||||
|
||||
@BinaryAnnotation
|
||||
class BinaryUsage
|
||||
|
||||
@RuntimeAnnotation
|
||||
class RuntimeUsage
|
||||
+36
-8
@@ -16,12 +16,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestCase
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestUtil
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
@@ -29,13 +31,26 @@ import java.io.File
|
||||
import java.io.StringWriter
|
||||
|
||||
abstract class AbstractAnnotationProcessorBoxTest : CodegenTestCase() {
|
||||
override fun doTest(path: String) {
|
||||
val testName = getTestName(true)
|
||||
val ktFiles = File(path).listFiles { file -> file.isFile && file.extension.toLowerCase() == "kt" }
|
||||
val testFiles = ktFiles.map { TestFile(it.name, it.readText()) }
|
||||
val supportInheritedAnnotations = testName.startsWith("inherited")
|
||||
override fun doTest(path: String) {
|
||||
val testDir = File(path)
|
||||
|
||||
val collectorExtension = createTestEnvironment(supportInheritedAnnotations)
|
||||
fun filesByExtension(ext: String) = testDir.listFiles { file -> file.isFile && file.extension.equals(ext, ignoreCase = true) }
|
||||
|
||||
val testName = getTestName(true)
|
||||
val ktFiles = filesByExtension("kt")
|
||||
val testFiles = ktFiles.map { TestFile(it.name, it.readText()) }
|
||||
val supportInheritedAnnotations = testName.contains("inherited", ignoreCase = true)
|
||||
val supportStubs = testName.contains("stubs", ignoreCase = true)
|
||||
|
||||
val javaSourceRoots = mutableListOf<File>()
|
||||
val javaFiles = filesByExtension("java")
|
||||
if (javaFiles.isNotEmpty()) {
|
||||
val javaFilesDir = KotlinTestUtils.tmpDir("java-files")
|
||||
javaFiles.forEach { it.copyTo(File(javaFilesDir, it.name)) }
|
||||
javaSourceRoots.add(javaFilesDir)
|
||||
}
|
||||
|
||||
val collectorExtension = createTestEnvironment(supportInheritedAnnotations, supportStubs, javaSourceRoots)
|
||||
loadMultiFiles(testFiles)
|
||||
CodegenTestUtil.generateFiles(myEnvironment, myFiles)
|
||||
|
||||
@@ -49,14 +64,27 @@ abstract class AbstractAnnotationProcessorBoxTest : CodegenTestCase() {
|
||||
return "plugins/annotation-collector/testData/codegen/"
|
||||
}
|
||||
|
||||
private fun createTestEnvironment(supportInheritedAnnotations: Boolean): AnnotationCollectorExtensionForTests {
|
||||
val configuration = KotlinTestUtils.compilerConfigurationForTests(ConfigurationKind.ALL, TestJdkKind.MOCK_JDK)
|
||||
private fun createTestEnvironment(
|
||||
supportInheritedAnnotations: Boolean,
|
||||
supportStubs: Boolean,
|
||||
javaSourceRoots: List<File>
|
||||
): AnnotationCollectorExtensionForTests {
|
||||
val configuration = KotlinTestUtils.compilerConfigurationForTests(ConfigurationKind.ALL,
|
||||
TestJdkKind.MOCK_JDK,
|
||||
/* classpath = */ emptyList(),
|
||||
javaSourceRoots)
|
||||
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable!!, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
val project = environment.project
|
||||
|
||||
val collectorExtension = AnnotationCollectorExtensionForTests(supportInheritedAnnotations)
|
||||
ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension)
|
||||
|
||||
if (supportStubs) {
|
||||
val stubsDir = KotlinTestUtils.tmpDir("class-stubs")
|
||||
val stubProducerExtension = StubProducerExtension(stubsDir, MessageCollector.NONE)
|
||||
AnalysisCompletedHandlerExtension.registerExtension(project, stubProducerExtension)
|
||||
}
|
||||
|
||||
myEnvironment = environment
|
||||
|
||||
return collectorExtension
|
||||
|
||||
+30
@@ -83,6 +83,12 @@ public class AnnotationProcessorBoxTestGenerated extends AbstractAnnotationProce
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritedSimple")
|
||||
public void testInheritedSimple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/inheritedSimple/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritedTopLevel")
|
||||
public void testInheritedTopLevel() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/inheritedTopLevel/");
|
||||
@@ -125,6 +131,30 @@ public class AnnotationProcessorBoxTestGenerated extends AbstractAnnotationProce
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("retentionPoliciesJavaAnnotations")
|
||||
public void testRetentionPoliciesJavaAnnotations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/retentionPoliciesJavaAnnotations/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("retentionPoliciesJavaAnnotationsStubs")
|
||||
public void testRetentionPoliciesJavaAnnotationsStubs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/retentionPoliciesJavaAnnotationsStubs/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("retentionPoliciesKotlinAnnotations")
|
||||
public void testRetentionPoliciesKotlinAnnotations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/retentionPoliciesKotlinAnnotations/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("retentionPoliciesKotlinAnnotationsStubs")
|
||||
public void testRetentionPoliciesKotlinAnnotationsStubs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/retentionPoliciesKotlinAnnotationsStubs/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelAnnotated")
|
||||
public void testTopLevelAnnotated() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/annotation-collector/testData/collectToFile/topLevelAnnotated/");
|
||||
|
||||
Reference in New Issue
Block a user