From 64046f1e40e9db0d980acc294f6dad8cd64e78be Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 28 Oct 2016 20:40:15 +0300 Subject: [PATCH] Kapt3: Add simple AP test with Kotlin --- .../kotlin/generators/tests/GenerateTests.kt | 5 + .../org/jetbrains/kotlin/kapt3/KaptRunner.kt | 13 ++- .../kotlin/kapt3/SyntheticJavaFileObject.kt | 13 ++- .../kapt3/test/AbstractJCTreeConverterTest.kt | 63 ---------- .../kapt3/test/AbstractKotlinKapt3Test.kt | 110 ++++++++++++++++++ .../kotlin/kapt3/test/KaptRunnerTest.kt | 4 +- .../test/KotlinKaptRunnerTestGenerated.java | 43 +++++++ plugins/kapt3/testData/kotlinRunner/Simple.kt | 19 +++ .../kapt3/testData/kotlinRunner/Simple.txt | 4 + plugins/plugins-tests/plugins-tests.iml | 1 + 10 files changed, 206 insertions(+), 69 deletions(-) delete mode 100644 plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt create mode 100644 plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt create mode 100644 plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKaptRunnerTestGenerated.java create mode 100644 plugins/kapt3/testData/kotlinRunner/Simple.kt create mode 100644 plugins/kapt3/testData/kotlinRunner/Simple.txt diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index 20d07fca238..f4e3447ac0e 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -137,6 +137,7 @@ import org.jetbrains.kotlin.jvm.compiler.* import org.jetbrains.kotlin.jvm.runtime.AbstractJvm8RuntimeDescriptorLoaderTest import org.jetbrains.kotlin.jvm.runtime.AbstractJvmRuntimeDescriptorLoaderTest import org.jetbrains.kotlin.kapt3.test.AbstractJCTreeConverterTest +import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptRunnerTest import org.jetbrains.kotlin.kdoc.AbstractKDocLexerTest import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBoxTest import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBytecodeShapeTest @@ -1142,6 +1143,10 @@ fun main(args: Array) { testClass { model("converter") } + + testClass { + model("kotlinRunner") + } } testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") { diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt index 30c98de4138..a2c4e55ffc7 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/KaptRunner.kt @@ -23,6 +23,7 @@ import com.sun.tools.javac.main.Option import com.sun.tools.javac.processing.AnnotationProcessingError import com.sun.tools.javac.processing.JavacProcessingEnvironment import com.sun.tools.javac.tree.JCTree +import com.sun.tools.javac.tree.TreeMaker import com.sun.tools.javac.util.Context import com.sun.tools.javac.util.Options import java.io.File @@ -51,6 +52,7 @@ class KaptError : RuntimeException { class KaptRunner { val context = Context() val compiler: KaptJavaCompiler + val fileManager: JavacFileManager private val options: Options init { @@ -58,11 +60,17 @@ class KaptRunner { KaptTreeMaker.preRegister(context) KaptJavaCompiler.preRegister(context) + fileManager = context.get(JavaFileManager::class.java) as JavacFileManager compiler = JavaCompiler.instance(context) as KaptJavaCompiler options = Options.instance(context) } + fun close() { + compiler.close() + fileManager.close() + } + fun parseJavaFiles( javaSourceFiles: List, classpath: List @@ -85,7 +93,8 @@ class KaptRunner { processors: List, classpath: List, sourceOutputDir: File, - classOutputDir: File + classOutputDir: File, + additionalSources: JavacList = JavacList.nil() ) { options.put(Option.PROC, "only") // Only process annotations classpath.forEach { options.put(Option.CLASSPATH, it.canonicalPath) } @@ -106,7 +115,7 @@ class KaptRunner { val compilerAfterAnnotationProcessing: JavaCompiler? = null try { - compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles)) + compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles + additionalSources)) } catch (e: AnnotationProcessingError) { throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e) } diff --git a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SyntheticJavaFileObject.kt b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SyntheticJavaFileObject.kt index 167677fae34..8ff8fbfe049 100644 --- a/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SyntheticJavaFileObject.kt +++ b/plugins/kapt3/src/org/jetbrains/kotlin/kapt3/SyntheticJavaFileObject.kt @@ -36,11 +36,20 @@ class SyntheticJavaFileObject( override fun inferBinaryName(path: MutableIterable?) = throw UnsupportedOperationException() - override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?) = true + override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?): Boolean { + if (simpleName == null || kind == null) return false + return this.kind == kind && simpleName == clazz.simpleName.toString() + } override fun getKind() = JavaFileObject.Kind.SOURCE - override fun getName() = compilationUnit.packageName.toString().replace('.', '/') + clazz.name + ".java" + override fun getName(): String { + val packageName = compilationUnit.packageName + if (packageName == null || packageName.toString() == "") { + return clazz.name.toString() + ".java" + } + return packageName.toString().replace('.', '/') + '/' + clazz.simpleName.toString() + ".java" + } override fun getAccessLevel(): Modifier? { val flags = clazz.modifiers.getFlags() diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt deleted file mode 100644 index a095093ef12..00000000000 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractJCTreeConverterTest.kt +++ /dev/null @@ -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.kapt3.test - -import com.intellij.openapi.util.text.StringUtil -import com.sun.tools.javac.comp.CompileStates -import org.jetbrains.kotlin.codegen.CodegenTestCase -import org.jetbrains.kotlin.codegen.CodegenTestUtil -import org.jetbrains.kotlin.kapt3.JCTreeConverter -import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory -import org.jetbrains.kotlin.kapt3.KaptRunner -import org.jetbrains.kotlin.test.ConfigurationKind -import org.jetbrains.kotlin.test.KotlinTestUtils -import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF -import java.io.File - -abstract class AbstractJCTreeConverterTest : CodegenTestCase() { - override fun doMultiFileTest(wholeFile: File, files: List, javaFilesDir: File?) { - val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray() - - createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources) - loadMultiFiles(files) - - val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt") - val classBuilderFactory = Kapt3BuilderFactory() - val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory) - val typeMapper = factory.generationState.typeMapper - - val kaptRunner = KaptRunner() - try { - val converter = JCTreeConverter(kaptRunner.context, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins) - val javaFiles = converter.convert() - - kaptRunner.compiler.enterTrees(javaFiles) - - val actualRaw = javaFiles.joinToString ("\n\n////////////////////\n\n") - val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF() - - if (kaptRunner.compiler.shouldStop(CompileStates.CompileState.ENTER)) { - error("There were errors during analysis. See errors above. Stubs:\n\n$actual") - } - - KotlinTestUtils.assertEqualsToFile(txtFile, actual) - } finally { - kaptRunner.compiler.close() - } - } -} - diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt new file mode 100644 index 00000000000..4a34de64d9c --- /dev/null +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -0,0 +1,110 @@ +/* + * 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.kapt3.test + +import com.intellij.openapi.util.text.StringUtil +import com.sun.tools.javac.comp.CompileStates +import com.sun.tools.javac.tree.JCTree +import org.jetbrains.kotlin.codegen.CodegenTestCase +import org.jetbrains.kotlin.codegen.CodegenTestUtil +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.kapt3.JCTreeConverter +import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory +import org.jetbrains.kotlin.kapt3.KaptRunner +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin +import org.jetbrains.kotlin.test.ConfigurationKind +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF +import org.jetbrains.org.objectweb.asm.tree.ClassNode +import com.sun.tools.javac.util.List as JavacList +import java.io.File +import java.nio.file.Files + +abstract class AbstractKotlinKapt3Test : CodegenTestCase() { + protected companion object { + val FILE_SEPARATOR = "\n\n////////////////////\n\n" + } + + override fun doMultiFileTest(wholeFile: File, files: List, javaFilesDir: File?) { + val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray() + + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources) + loadMultiFiles(files) + + val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt") + val classBuilderFactory = Kapt3BuilderFactory() + val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory) + val typeMapper = factory.generationState.typeMapper + + val kaptRunner = KaptRunner() + try { + check(kaptRunner, typeMapper, classBuilderFactory, txtFile) + } finally { + kaptRunner.close() + } + } + + protected fun convert( + kaptRunner: KaptRunner, + typeMapper: KotlinTypeMapper, + compiledClasses: List, + origins: Map + ): JavacList { + val converter = JCTreeConverter(kaptRunner.context, typeMapper, compiledClasses, origins) + return converter.convert() + } + + protected abstract fun check( + kaptRunner: KaptRunner, + typeMapper: KotlinTypeMapper, + classBuilderFactory: Kapt3BuilderFactory, + txtFile: File) +} + +abstract class AbstractJCTreeConverterTest : AbstractKotlinKapt3Test() { + override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) { + val javaFiles = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins) + kaptRunner.compiler.enterTrees(javaFiles) + + val actualRaw = javaFiles.joinToString (FILE_SEPARATOR) + val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF() + + if (kaptRunner.compiler.shouldStop(CompileStates.CompileState.ENTER)) { + error("There were errors during analysis. See errors above. Stubs:\n\n$actual") + } + KotlinTestUtils.assertEqualsToFile(txtFile, actual) + } +} + +abstract class AbstractKotlinKaptRunnerTest : AbstractKotlinKapt3Test() { + override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) { + val compilationUnits = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins) + val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile() + try { + kaptRunner.doAnnotationProcessing(emptyList(), listOf(KaptRunnerTest.SIMPLE_PROCESSOR), + classpath = listOf(), sourceOutputDir = sourceOutputDir, classOutputDir = sourceOutputDir, + additionalSources = compilationUnits) + + val javaFiles = sourceOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" } + val actualRaw = javaFiles.sortedBy { it.name }.joinToString(FILE_SEPARATOR) { it.name + ":\n\n" + it.readText() } + val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF() + KotlinTestUtils.assertEqualsToFile(txtFile, actual) + } finally { + sourceOutputDir.deleteRecursively() + } + } +} \ No newline at end of file diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KaptRunnerTest.kt b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KaptRunnerTest.kt index 3acd688842c..4490ca05714 100644 --- a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KaptRunnerTest.kt +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KaptRunnerTest.kt @@ -43,8 +43,8 @@ import javax.lang.model.element.TypeElement */ class KaptRunnerTest { - private companion object { - val TEST_DATA_DIR = File("plugins/kapt3/testData/runner") + companion object { + private val TEST_DATA_DIR = File("plugins/kapt3/testData/runner") val SIMPLE_PROCESSOR = object : AbstractProcessor() { override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { diff --git a/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKaptRunnerTestGenerated.java b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKaptRunnerTestGenerated.java new file mode 100644 index 00000000000..eebdd90f0e3 --- /dev/null +++ b/plugins/kapt3/test/org/jetbrains/kotlin/kapt3/test/KotlinKaptRunnerTestGenerated.java @@ -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.kapt3.test; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("plugins/kapt3/testData/kotlinRunner") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class KotlinKaptRunnerTestGenerated extends AbstractKotlinKaptRunnerTest { + public void testAllFilesPresentInKotlinRunner() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/testData/kotlinRunner"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("Simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/kotlinRunner/Simple.kt"); + doTest(fileName); + } +} diff --git a/plugins/kapt3/testData/kotlinRunner/Simple.kt b/plugins/kapt3/testData/kotlinRunner/Simple.kt new file mode 100644 index 00000000000..fb348eb9478 --- /dev/null +++ b/plugins/kapt3/testData/kotlinRunner/Simple.kt @@ -0,0 +1,19 @@ +package test + +internal class Simple { + @MyAnnotation + fun myMethod() { + // do nothing + } +} + +internal annotation class MyAnnotation + +internal enum class EnumClass { + BLACK, WHITE +} + + +internal enum class EnumClass2 private constructor(private val blah: String) { + WHITE("A"), RED("B") +} \ No newline at end of file diff --git a/plugins/kapt3/testData/kotlinRunner/Simple.txt b/plugins/kapt3/testData/kotlinRunner/Simple.txt new file mode 100644 index 00000000000..214dd6af195 --- /dev/null +++ b/plugins/kapt3/testData/kotlinRunner/Simple.txt @@ -0,0 +1,4 @@ +MyMethodMyAnnotation.java: + +package generated; +class MyMethodMyAnnotation {} diff --git a/plugins/plugins-tests/plugins-tests.iml b/plugins/plugins-tests/plugins-tests.iml index 6e288b5b2cd..b9fed3f8dd0 100755 --- a/plugins/plugins-tests/plugins-tests.iml +++ b/plugins/plugins-tests/plugins-tests.iml @@ -36,5 +36,6 @@ + \ No newline at end of file