diff --git a/.idea/modules.xml b/.idea/modules.xml
index 021661f45d5..7be217f18b4 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -68,6 +68,7 @@
+
diff --git a/plugins/kapt3/kapt3.iml b/plugins/kapt3/kapt3.iml
new file mode 100644
index 00000000000..b87c6efed97
--- /dev/null
+++ b/plugins/kapt3/kapt3.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/kapt3/src/KaptJavaCompiler.kt b/plugins/kapt3/src/KaptJavaCompiler.kt
new file mode 100644
index 00000000000..4adc7cb5deb
--- /dev/null
+++ b/plugins/kapt3/src/KaptJavaCompiler.kt
@@ -0,0 +1,31 @@
+/*
+ * 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
+
+import com.sun.tools.javac.comp.CompileStates
+import com.sun.tools.javac.main.JavaCompiler
+import com.sun.tools.javac.util.Context
+
+class KaptJavaCompiler(context: Context) : JavaCompiler(context) {
+ public override fun shouldStop(cs: CompileStates.CompileState) = super.shouldStop(cs)
+
+ companion object {
+ fun preRegister(context: Context) {
+ context.put(compilerKey, Context.Factory(::KaptJavaCompiler))
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/kapt3/src/KaptRunner.kt b/plugins/kapt3/src/KaptRunner.kt
new file mode 100644
index 00000000000..a3c93ba6ef0
--- /dev/null
+++ b/plugins/kapt3/src/KaptRunner.kt
@@ -0,0 +1,69 @@
+/*
+ * 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
+
+import com.sun.tools.javac.comp.CompileStates
+import com.sun.tools.javac.file.JavacFileManager
+import com.sun.tools.javac.main.JavaCompiler
+import com.sun.tools.javac.main.Option
+import com.sun.tools.javac.processing.JavacProcessingEnvironment
+import com.sun.tools.javac.util.Context
+import com.sun.tools.javac.util.Log
+import com.sun.tools.javac.util.Options
+import java.io.File
+import java.io.PrintWriter
+import javax.annotation.processing.Processor
+import javax.tools.JavaFileManager
+
+class KaptError : RuntimeException {
+ constructor(message: String) : super(message)
+ constructor(message: String, cause: Throwable) : super(message, cause)
+}
+
+class KaptRunner {
+ fun doAnnotationProcessing(javaSourceFiles: List, processors: List, sourceOutputDir: File, classOutputDir: File) {
+ val context = Context()
+ JavacFileManager.preRegister(context)
+ KaptJavaCompiler.preRegister(context)
+
+ val options = Options.instance(context)
+ context.put(Log.outKey, PrintWriter(System.err, true))
+ options.put(Option.PROC, "only") // Only process annotations
+ options.put(Option.S, sourceOutputDir.canonicalPath)
+ options.put(Option.D, classOutputDir.canonicalPath)
+
+ val fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
+ val compiler = JavaCompiler.instance(context) as KaptJavaCompiler
+ val processingEnvironment = JavacProcessingEnvironment.instance(context)
+
+ try {
+ compiler.initProcessAnnotations(processors)
+
+ val javaFileObjects = fileManager.getJavaFileObjectsFromFiles(javaSourceFiles)
+ val parsedJavaFiles = compiler.parseFiles(javaFileObjects)
+ if (compiler.shouldStop(CompileStates.CompileState.PARSE)) {
+ throw KaptError("Error while parsing Java files.")
+ }
+
+ val compilerAfterAnnotationProcessing = compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles))
+ compilerAfterAnnotationProcessing.close()
+ } finally {
+ processingEnvironment.close()
+ fileManager.close()
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/kapt3/test/KaptRunnerTest.kt b/plugins/kapt3/test/KaptRunnerTest.kt
new file mode 100644
index 00000000000..959fa9f33f9
--- /dev/null
+++ b/plugins/kapt3/test/KaptRunnerTest.kt
@@ -0,0 +1,71 @@
+import org.jetbrains.kotlin.kapt3.KaptRunner
+import org.junit.Assert
+import org.junit.Assert.*
+import org.junit.Test
+import java.io.File
+import java.nio.file.Files
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.element.TypeElement
+
+/*
+ * 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.
+ */
+
+class KaptRunnerTest {
+ private companion object {
+ val TEST_DATA_DIR = File("plugins/kapt3/testData/runner")
+ }
+
+ @Test
+ fun testSimple() {
+ val processor = object : AbstractProcessor() {
+ override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean {
+ for (annotation in annotations) {
+ val annotationName = annotation.simpleName.toString()
+ val annotatedElements = roundEnv.getElementsAnnotatedWith(annotation)
+
+ for (annotatedElement in annotatedElements) {
+ val generatedClassName = annotatedElement.simpleName.toString().capitalize() + annotationName.capitalize()
+ val file = processingEnv.filer.createSourceFile("generated." + generatedClassName)
+ file.openWriter().use {
+ it.write("""
+ package generated;
+ class $generatedClassName {}
+ """.trimIndent())
+ }
+ }
+ }
+
+ return true;
+ }
+
+ override fun getSupportedAnnotationTypes() = setOf("test.MyAnnotation")
+ }
+
+ val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
+ try {
+ KaptRunner().doAnnotationProcessing(
+ listOf(File(TEST_DATA_DIR, "Simple.java")),
+ listOf(processor),
+ sourceOutputDir,
+ sourceOutputDir)
+ val myMethodFile = File(sourceOutputDir, "generated/MyMethodMyAnnotation.java")
+ assertTrue(myMethodFile.exists())
+ } finally {
+ sourceOutputDir.deleteRecursively()
+ }
+ }
+}
\ No newline at end of file
diff --git a/plugins/kapt3/testData/runner/Simple.java b/plugins/kapt3/testData/runner/Simple.java
new file mode 100644
index 00000000000..f2807ab9651
--- /dev/null
+++ b/plugins/kapt3/testData/runner/Simple.java
@@ -0,0 +1,12 @@
+package test;
+
+class Simple {
+ @MyAnnotation
+ void myMethod() {
+ // do nothing
+ }
+}
+
+@interface MyAnnotation {
+
+}
\ No newline at end of file