diff --git a/.idea/modules.xml b/.idea/modules.xml
index 6d8f9759829..e424833dd6f 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -10,6 +10,7 @@
+
@@ -52,6 +53,7 @@
+
diff --git a/plugins/annotation-processing/annotation-processing.iml b/plugins/annotation-processing/annotation-processing.iml
new file mode 100644
index 00000000000..81a78835658
--- /dev/null
+++ b/plugins/annotation-processing/annotation-processing.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingConfigurationService.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingConfigurationService.kt
new file mode 100644
index 00000000000..88bb8a0d63a
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingConfigurationService.kt
@@ -0,0 +1,19 @@
+/*
+ * 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.processing
+
+class AnnotationProcessingConfigurationService(val aptClassLoader: ClassLoader)
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingExtension.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingExtension.kt
new file mode 100644
index 00000000000..b08b1c953c3
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingExtension.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.intellij.openapi.project.Project
+import com.intellij.psi.*
+import com.intellij.psi.search.GlobalSearchScope
+import org.jetbrains.kotlin.analyzer.AnalysisResult
+import org.jetbrains.kotlin.annotation.processing.impl.*
+import org.jetbrains.kotlin.asJava.findFacadeClass
+import org.jetbrains.kotlin.asJava.toLightClass
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.java.model.elements.JeTypeElement
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
+import java.io.File
+import java.net.URLClassLoader
+import java.util.*
+import javax.annotation.processing.Processor
+
+class AnnotationProcessingExtension(
+ val generatedOutputDir: File,
+ val annotationProcessingClasspath: List
+) : AnalysisCompletedHandlerExtension {
+ private var annotationProcessingComplete = false
+
+ override fun analysisCompleted(
+ project: Project,
+ module: ModuleDescriptor,
+ bindingContext: BindingContext,
+ files: Collection
+ ): AnalysisResult? {
+ if (annotationProcessingComplete) {
+ return null
+ }
+
+ val processors = loadAnnotationProcessors(annotationProcessingClasspath)
+ if (processors.isEmpty()) return null
+
+ val analysisContext = AnalysisContext(hashMapOf())
+ analysisContext.analyzeFiles(files)
+
+ val options = emptyMap()
+
+ val javaPsiFacade = JavaPsiFacade.getInstance(project)
+ val projectScope = GlobalSearchScope.projectScope(project)
+
+ val filer = KotlinFiler(generatedOutputDir)
+ val messages = KotlinMessager()
+ val types = KotlinTypes(javaPsiFacade, projectScope)
+ val elements = KotlinElements(javaPsiFacade, projectScope)
+
+ val processingEnvironment = KotlinProcessingEnvironment(elements, types, messages, options, filer)
+ processors.forEach { it.init(processingEnvironment) }
+
+
+ // Round 1
+ val round1Environment = KotlinRoundEnvironment(analysisContext)
+ for (processor in processors) {
+ val supportedAnnotationNames = processor.supportedAnnotationTypes.filter { it in analysisContext.annotationsMap }
+ if (supportedAnnotationNames.isEmpty()) continue
+
+ val supportedAnnotations = supportedAnnotationNames
+ .map { javaPsiFacade.findClass(it, projectScope)?.let { JeTypeElement(it) } }
+ .filterNotNullTo(hashSetOf())
+
+ processor.process(supportedAnnotations, round1Environment)
+ }
+
+ // Round 2
+ val round2Environment = KotlinRoundEnvironment(AnalysisContext(hashMapOf()), isProcessingOver = true)
+ for (processor in processors) {
+ processor.process(emptySet(), round2Environment)
+ }
+
+ annotationProcessingComplete = true
+ return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedOutputDir))
+ }
+
+ private fun loadAnnotationProcessors(classpath: List): List {
+ val classLoader = URLClassLoader(classpath.map { File(it).toURI().toURL() }.toTypedArray())
+ return ServiceLoader.load(Processor::class.java, classLoader).toList()
+ }
+}
+
+internal class AnalysisContext(val annotationsMap: MutableMap>)
+
+private fun AnalysisContext.analyzeFiles(files: Collection) {
+ for (file in files) {
+ analyzeFile(file)
+ }
+}
+
+private fun AnalysisContext.analyzeFile(file: KtFile) {
+ val lightClass = file.findFacadeClass()
+
+ if (lightClass != null) {
+ analyzeDeclaration(lightClass)
+ }
+
+ for (declaration in file.declarations) {
+ if (declaration !is KtClassOrObject) continue
+ val clazz = declaration.toLightClass() ?: continue
+ analyzeDeclaration(clazz)
+ }
+}
+
+private fun AnalysisContext.analyzeDeclaration(declaration: PsiElement) {
+ if (declaration !is PsiModifierListOwner) return
+
+ val annotations = declaration.modifierList?.annotations
+ if (annotations != null) {
+ for (annotation in annotations) {
+ val fqName = annotation.qualifiedName ?: continue
+ annotationsMap.getOrPut(fqName, { mutableListOf() }).add(declaration)
+ }
+ }
+
+ if (declaration is PsiClass) {
+ declaration.methods.forEach { analyzeDeclaration(it) }
+ declaration.fields.forEach { analyzeDeclaration(it) }
+ declaration.innerClasses.forEach { analyzeDeclaration(it) }
+ }
+
+ when (declaration) {
+ is KtClassOrObject -> declaration.declarations.forEach { analyzeDeclaration(it) }
+
+ }
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingPlugin.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingPlugin.kt
new file mode 100644
index 00000000000..1e25d5486bc
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/AnnotationProcessingPlugin.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.processing
+
+import com.intellij.mock.MockProject
+import org.jetbrains.kotlin.annotation.AnnotationProcessingExtension
+import org.jetbrains.kotlin.compiler.plugin.CliOption
+import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
+import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
+import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.config.CompilerConfigurationKey
+import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
+import java.io.File
+
+object AnnotationProcessingConfigurationKeys {
+ val GENERATED_OUTPUT_DIR: CompilerConfigurationKey =
+ CompilerConfigurationKey.create("generated files output directory")
+
+ val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey> =
+ CompilerConfigurationKey.create>("annotation processor classpath")
+}
+
+class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
+ companion object {
+ val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt2"
+
+ val GENERATED_OUTPUT_DIR_OPTION: CliOption =
+ CliOption("generated", "", "Output path for generated files", required = false)
+
+ val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
+ CliOption("apclasspath", "", "Annotation processor classpath",
+ required = false, allowMultipleOccurrences = true)
+ }
+
+ override val pluginId: String = ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID
+
+ override val pluginOptions: Collection =
+ listOf(GENERATED_OUTPUT_DIR_OPTION, ANNOTATION_PROCESSOR_CLASSPATH_OPTION)
+
+ override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
+ when (option) {
+ ANNOTATION_PROCESSOR_CLASSPATH_OPTION -> {
+ val paths = configuration.getList(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH).toMutableList()
+ paths.add(value)
+ configuration.put(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH, paths)
+ }
+ GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
+ else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
+ }
+ }
+}
+
+class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
+ override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
+ val generatedOutputDir = configuration.get(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR) ?: return
+ val classpath = configuration.get(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH) ?: return
+
+ val generatedOutputDirFile = File(generatedOutputDir)
+ generatedOutputDirFile.mkdirs()
+
+ val annotationProcessingExtension = AnnotationProcessingExtension(generatedOutputDirFile, classpath)
+ AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
+ }
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt
new file mode 100644
index 00000000000..665ec769536
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinElements.kt
@@ -0,0 +1,202 @@
+/*
+ * 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.processing.impl
+
+import com.intellij.psi.JavaPsiFacade
+import com.intellij.psi.PsiClass
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.util.PsiSuperMethodUtil
+import com.intellij.psi.util.PsiTypesUtil
+import org.jetbrains.kotlin.java.model.JeAnnotationOwner
+import org.jetbrains.kotlin.java.model.JeElement
+import org.jetbrains.kotlin.java.model.JeName
+import org.jetbrains.kotlin.java.model.elements.JeAnnotationMirror
+import org.jetbrains.kotlin.java.model.elements.JeMethodExecutableElement
+import org.jetbrains.kotlin.java.model.elements.JePackageElement
+import org.jetbrains.kotlin.java.model.elements.JeTypeElement
+import java.io.PrintWriter
+import java.io.Writer
+import javax.lang.model.element.*
+import javax.lang.model.util.Elements
+
+class KotlinElements(val javaPsiFacade: JavaPsiFacade, val scope: GlobalSearchScope) : Elements {
+ override fun hides(hider: Element, hidden: Element): Boolean {
+ val hiderMethod = (hider as? JeMethodExecutableElement)?.psi ?: return false
+ val hiddenMethod = (hidden as? JeMethodExecutableElement)?.psi ?: return false
+
+ if (hiderMethod.name != hiddenMethod.name) return false
+ if (hiderMethod.parameterList.parametersCount != hiddenMethod.parameterList.parametersCount) return false
+
+ val hiderMethodClass = hiderMethod.containingClass ?: return false
+ val hiddenMethodClass = hiddenMethod.containingClass ?: return false
+
+ if (PsiTypesUtil.getClassType(hiddenMethodClass) !in hiderMethodClass.superTypes) return false
+
+ if (hiderMethod.returnType != hiddenMethod.returnType) return false
+ for (i in 0..hiderMethod.parameterList.parametersCount - 1) {
+ if (hiderMethod.parameterList.parameters[i].type != hiddenMethod.parameterList.parameters[i].type) return false
+ }
+
+ return true
+ }
+
+ override fun overrides(overrider: ExecutableElement, overridden: ExecutableElement, type: TypeElement): Boolean {
+ overrider as? JeMethodExecutableElement ?: return false
+ overridden as? JeMethodExecutableElement ?: return false
+
+ return PsiSuperMethodUtil.isSuperMethod(overrider.psi, overridden.psi)
+ }
+
+ override fun getName(cs: CharSequence?) = JeName(cs?.toString())
+
+ override fun getElementValuesWithDefaults(a: AnnotationMirror): Map {
+ a as? JeAnnotationMirror ?: return emptyMap()
+ return a.getAllElementValues()
+ }
+
+ override fun getBinaryName(type: TypeElement) = JeName((type as JeTypeElement).psi.qualifiedName)
+
+ override fun getDocComment(e: Element?) = ""
+
+ override fun isDeprecated(e: Element?): Boolean {
+ return (e as? JeAnnotationOwner)?.annotationOwner?.findAnnotation("java.lang.Deprecated") != null
+ }
+
+ override fun getAllMembers(type: TypeElement) = (type as? JeTypeElement)?.getAllMembers() ?: emptyList()
+
+ override fun printElements(w: Writer, vararg elements: Element) {
+ val printWriter = PrintWriter(w)
+ for (element in elements) {
+ printWriter.println(element.simpleName.toString() + " (" + element.javaClass.name + ")")
+ }
+ }
+
+ override fun getPackageElement(name: CharSequence): PackageElement? {
+ val psiPackage = javaPsiFacade.findPackage(name.toString()) ?: return null
+ return JePackageElement(psiPackage)
+ }
+
+ override fun getTypeElement(name: CharSequence): TypeElement? {
+ val psiClass = javaPsiFacade.findClass(name.toString(), scope) ?: return null
+ return JeTypeElement(psiClass)
+ }
+
+ override fun getConstantExpression(value: Any?) = Constants.format(value)
+
+ override tailrec fun getPackageOf(element: Element): PackageElement? {
+ if (element is PackageElement) return element
+ val parent = element.enclosingElement ?: return null
+ return getPackageOf(parent)
+ }
+
+ override fun getAllAnnotationMirrors(e: Element): List {
+ val annotations = (e as? JeElement)?.annotationMirrors?.toMutableList() ?: return emptyList()
+
+ if (e is JeTypeElement) {
+ var parent = e.psi.superClass
+ while (parent != null) {
+ val parentAnnotations = parent.modifierList?.annotations
+ if (parentAnnotations == null) {
+ parent = parent.superClass
+ continue
+ }
+
+ for (parentAnnotation in parentAnnotations) {
+ val annotationClass = parentAnnotation.nameReferenceElement?.resolve() as? PsiClass ?: continue
+ annotationClass.modifierList?.findAnnotation("java.lang.annotation.Inherited") ?: continue
+ annotations += JeAnnotationMirror(parentAnnotation)
+ }
+
+ parent = parent.superClass
+ }
+ }
+
+ return annotations
+ }
+
+ override fun isFunctionalInterface(type: TypeElement): Boolean {
+ val jeTypeElement = type as? JeTypeElement ?: return false
+ if (!jeTypeElement.psi.isInterface) return false
+ if (jeTypeElement.psi.allMethods.size != 1) return false
+ return true
+ }
+}
+
+object Constants {
+ fun format(value: Any?): String {
+ return when (value) {
+ is Byte -> formatByte((value as Byte?)!!)
+ is Short -> formatShort((value as Short?)!!)
+ is Long -> formatLong((value as Long?)!!)
+ is Float -> formatFloat((value as Float?)!!)
+ is Double -> formatDouble((value as Double?)!!)
+ is Char -> formatChar(value)
+ is String -> formatString(value)
+ is Int, is Boolean -> value.toString()
+ else -> throw IllegalArgumentException(
+ "Argument is not a primitive type or a string; it " +
+ (if (value == null) "is a null value." else "has class " + value.javaClass.name) + ".")
+ }
+ }
+
+ private fun formatByte(b: Byte) = String.format("(byte)0x%02x", b)
+ private fun formatShort(s: Short) = String.format("(short)%d", s)
+ private fun formatLong(lng: Long) = "${lng}L"
+ private fun formatChar(c: Char) = '\'' + quote(c) + '\''
+ private fun formatString(s: String) = '"' + quote(s) + '"'
+
+ private fun formatFloat(f: Float): String {
+ if (java.lang.Float.isNaN(f))
+ return "0.0f/0.0f"
+ else if (java.lang.Float.isInfinite(f))
+ return if (f < 0) "-1.0f/0.0f" else "1.0f/0.0f"
+ else
+ return "${f}f"
+ }
+
+ private fun formatDouble(d: Double): String {
+ if (java.lang.Double.isNaN(d))
+ return "0.0/0.0"
+ else if (java.lang.Double.isInfinite(d))
+ return if (d < 0) "-1.0/0.0" else "1.0/0.0"
+ else
+ return d.toString()
+ }
+
+ fun quote(ch: Char): String {
+ return when (ch) {
+ '\b' -> "\\b"
+ '\n' -> "\\n"
+ '\r' -> "\\r"
+ '\t' -> "\\t"
+ '\'' -> "\\'"
+ '\"' -> "\\\""
+ '\\' -> "\\\\"
+ else -> if (isPrintableAscii(ch)) ch.toString() else String.format("\\u%04x", ch.toInt())
+ }
+ }
+
+ fun quote(s: String): String {
+ val buf = StringBuilder()
+ for (i in 0..s.length - 1) {
+ buf.append(quote(s[i]))
+ }
+ return buf.toString()
+ }
+
+ private fun isPrintableAscii(ch: Char) = ch >= ' ' && ch <= '~'
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinFiler.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinFiler.kt
new file mode 100644
index 00000000000..8398785203a
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinFiler.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.processing.impl
+
+import java.io.File
+import javax.annotation.processing.Filer
+import javax.lang.model.element.Element
+import javax.tools.FileObject
+import javax.tools.JavaFileManager
+import javax.tools.JavaFileObject
+
+class KotlinFiler(val generatedDir: File) : Filer {
+ private companion object {
+ val PACKAGE_INFO_SUFFIX = ".packageInfo"
+ }
+
+ private var dotGeneratedGenerated = false
+
+ private fun createDotGeneratedIfNeeded() {
+ if (!dotGeneratedGenerated) {
+ dotGeneratedGenerated = true
+ File(generatedDir, ".generated").writeText("Generated by kapt2")
+ }
+ }
+
+ private fun getGeneratedFile(nameCharSequence: CharSequence, extension: String): File {
+ createDotGeneratedIfNeeded()
+
+ val name = nameCharSequence.toString()
+ val isPackageInfo = name.endsWith(PACKAGE_INFO_SUFFIX)
+ val fqName = if (isPackageInfo) name.substring(0, PACKAGE_INFO_SUFFIX.length) else name
+
+ val packageName = fqName.substringBeforeLast('.')
+
+ val packageDir = File(generatedDir, packageName.replace('.', '/'))
+ packageDir.mkdirs()
+
+ val fileName = fqName.substringAfterLast('.') + (if (isPackageInfo) PACKAGE_INFO_SUFFIX else extension)
+ return File(packageDir, fileName)
+ }
+
+ override fun createSourceFile(name: CharSequence, vararg originatingElements: Element?): JavaFileObject {
+ return KotlinJavaFileObject(getGeneratedFile(name, ".java"))
+ }
+
+ override fun getResource(location: JavaFileManager.Location, pkg: CharSequence, relativeName: CharSequence): FileObject? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun createResource(
+ location: JavaFileManager.Location?,
+ pkg: CharSequence,
+ relativeName: CharSequence,
+ vararg originatingElements: Element?
+ ): FileObject? {
+ throw UnsupportedOperationException()
+ }
+
+ override fun createClassFile(name: CharSequence, vararg originatingElements: Element?): JavaFileObject {
+ return KotlinJavaFileObject(getGeneratedFile(name, ".class"))
+ }
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinJavaFileObject.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinJavaFileObject.kt
new file mode 100644
index 00000000000..962522223d7
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinJavaFileObject.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.processing.impl
+
+import java.io.File
+import javax.tools.JavaFileObject
+
+class KotlinJavaFileObject(val file: File) : JavaFileObject {
+ override fun openOutputStream() = file.outputStream()
+
+ override fun getName() = file.name
+
+ override fun openWriter() = file.writer()
+
+ override fun openInputStream() = file.inputStream()
+
+ override fun getCharContent(ignoreEncodingErrors: Boolean): CharSequence? {
+ TODO()
+ }
+
+ override fun getLastModified() = file.lastModified()
+
+ override fun toUri() = file.toURI()
+
+ override fun openReader(ignoreEncodingErrors: Boolean) = file.reader()
+
+ override fun delete() = file.delete()
+
+ //TODO
+ override fun isNameCompatible(simpleName: String, kind: JavaFileObject.Kind) = true
+
+ override fun getKind() = when (file.extension) {
+ "class" -> JavaFileObject.Kind.CLASS
+ "java" -> JavaFileObject.Kind.SOURCE
+ "html" -> JavaFileObject.Kind.HTML
+ else -> JavaFileObject.Kind.OTHER
+ }
+
+ //TODO
+ override fun getAccessLevel() = null
+
+ //TODO
+ override fun getNestingKind() = null
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinMessager.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinMessager.kt
new file mode 100644
index 00000000000..ca1f2f9629f
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinMessager.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.processing.impl
+
+import javax.annotation.processing.Messager
+import javax.lang.model.element.AnnotationMirror
+import javax.lang.model.element.AnnotationValue
+import javax.lang.model.element.Element
+import javax.tools.Diagnostic
+
+class KotlinMessager : Messager {
+ override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence) = printMessage(kind, msg, null)
+
+ override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?) = printMessage(kind, msg, e, null)
+
+ override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?, a: AnnotationMirror?) {
+ printMessage(kind, msg, e, a, null)
+ }
+
+ override fun printMessage(kind: Diagnostic.Kind, msg: CharSequence, e: Element?, a: AnnotationMirror?, v: AnnotationValue?) {
+ println(msg)
+ }
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinProcessingEnvironment.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinProcessingEnvironment.kt
new file mode 100644
index 00000000000..c72898a80b7
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinProcessingEnvironment.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.processing.impl
+
+import java.util.*
+import javax.annotation.processing.ProcessingEnvironment
+import javax.lang.model.SourceVersion
+
+class KotlinProcessingEnvironment(
+ private val elements: KotlinElements,
+ private val types: KotlinTypes,
+ private val messager: KotlinMessager,
+ options: Map,
+ private val filer: KotlinFiler
+) : ProcessingEnvironment {
+ private val options = Collections.unmodifiableMap(options)
+
+ override fun getElementUtils() = elements
+ override fun getTypeUtils() = types
+ override fun getMessager() = messager
+ override fun getLocale() = Locale.getDefault()
+ override fun getSourceVersion() = SourceVersion.RELEASE_6
+ override fun getOptions() = options
+ override fun getFiler() = filer
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinRoundEnvironment.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinRoundEnvironment.kt
new file mode 100644
index 00000000000..c8f66a62b5e
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinRoundEnvironment.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.processing.impl
+
+import org.jetbrains.kotlin.annotation.AnalysisContext
+import org.jetbrains.kotlin.java.model.JeConverter
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.element.Element
+import javax.lang.model.element.TypeElement
+
+internal class KotlinRoundEnvironment(
+ private val context: AnalysisContext,
+ private val isProcessingOver: Boolean = false) : RoundEnvironment {
+ private var isError = false
+
+ override fun getRootElements() = emptySet()
+
+ override fun processingOver() = isProcessingOver
+
+ private fun getElementsAnnotatedWith(fqName: String): Set {
+ val declarations = context.annotationsMap[fqName] ?: return emptySet()
+ return hashSetOf().apply {
+ for (declaration in declarations) {
+ JeConverter.convert(declaration)?.let { add(it) }
+ }
+ }
+ }
+
+ override fun getElementsAnnotatedWith(a: TypeElement) = getElementsAnnotatedWith(a.qualifiedName.toString())
+ override fun getElementsAnnotatedWith(a: Class) = getElementsAnnotatedWith(a.canonicalName)
+
+ override fun errorRaised() = isError
+}
\ No newline at end of file
diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinTypes.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinTypes.kt
new file mode 100644
index 00000000000..e372315e387
--- /dev/null
+++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/impl/KotlinTypes.kt
@@ -0,0 +1,221 @@
+/*
+ * 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.processing.impl
+
+import com.intellij.psi.*
+import com.intellij.psi.impl.PsiSubstitutorImpl
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.util.PsiTypesUtil
+import com.intellij.psi.util.TypeConversionUtil
+import org.jetbrains.kotlin.java.model.elements.JeClassInitializerExecutableElement
+import org.jetbrains.kotlin.java.model.elements.JeMethodExecutableElement
+import org.jetbrains.kotlin.java.model.elements.JeTypeElement
+import org.jetbrains.kotlin.java.model.elements.JeVariableElement
+import org.jetbrains.kotlin.java.model.types.*
+import javax.lang.model.element.Element
+import javax.lang.model.element.TypeElement
+import javax.lang.model.type.*
+import javax.lang.model.util.Types
+
+class KotlinTypes(val javaPsiFacade: JavaPsiFacade, val scope: GlobalSearchScope) : Types {
+ override fun contains(t1: TypeMirror, t2: TypeMirror): Boolean {
+ t1 as? JeAbstractType ?: return false
+ t2 as? JeAbstractType ?: return false
+
+ val classType = t1.psiType as? PsiClassType ?: return false
+ return t2.psiType in classType.parameters
+ }
+
+ override fun getArrayType(componentType: TypeMirror): ArrayType {
+ val psiType = (componentType as? JeAbstractType)?.psiType
+ ?: throw IllegalArgumentException("Invalid component type: $componentType")
+ return JeArrayType(PsiArrayType(psiType))
+ }
+
+ override fun isAssignable(t1: TypeMirror, t2: TypeMirror): Boolean {
+ fun error(t: TypeMirror?): Nothing = throw IllegalArgumentException("Invalid type: $t")
+ if (t1 is ExecutableType || t1 is NoType) error(t1)
+ if (t2 is ExecutableType || t2 is NoType) error(t2)
+
+ t1 as? JeAbstractType ?: return false
+ t2 as? JeAbstractType ?: return false
+ return t1.psiType.isAssignableFrom(t2.psiType)
+ }
+
+ override fun getNullType() = JeNullType
+
+ override fun getWildcardType(extendsBound: TypeMirror, superBound: TypeMirror): JeWildcardTypeWithBounds {
+ return JeWildcardTypeWithBounds(extendsBound, superBound)
+ }
+
+ override fun unboxedType(t: TypeMirror): PrimitiveType? {
+ fun error(): Nothing = throw IllegalArgumentException("This type could not be unboxed: $t")
+ t as? JeAbstractType ?: error()
+ val unboxedType = PsiPrimitiveType.getUnboxedType(t.psiType) ?: error()
+ return unboxedType.toJePrimitiveType()
+ }
+
+ override fun getPrimitiveType(kind: TypeKind) = kind.toJePrimitiveType()
+
+ override fun erasure(t: TypeMirror): TypeMirror {
+ if (t is NoType) throw IllegalArgumentException("Invalid type: $t")
+ t as? JeAbstractType ?: return t
+ return TypeConversionUtil.erasure(t.psiType).toJeType()
+ }
+
+ override fun directSupertypes(t: TypeMirror): List {
+ if (t is NoType) throw IllegalArgumentException("Invalid type: $t")
+ val psiType = (t as? JeAbstractType)?.psiType as? PsiClassType ?: return emptyList()
+ return psiType.superTypes.map { it.toJeType() }
+ }
+
+ override fun boxedClass(p: PrimitiveType): TypeElement? {
+ p as? JePrimitiveType ?: throw IllegalArgumentException("Unknown type: $p")
+ val boxedTypeName = p.psiType.boxedTypeName
+ val boxedClass = javaPsiFacade.findClass(boxedTypeName, scope)
+ ?: throw IllegalStateException("Can't find boxed class $boxedTypeName")
+ return JeTypeElement(boxedClass)
+ }
+
+ override fun asElement(t: TypeMirror): Element? {
+ if (t is JeDeclaredType) {
+ return t.asElement()
+ } else if (t is JeTypeVariableType) {
+ return t.asElement()
+ }
+
+ return null
+ }
+
+ override fun isSubtype(t1: TypeMirror, t2: TypeMirror): Boolean {
+ val psiType1 = (t1 as? JeAbstractType)?.psiType ?: return false
+ val psiType2 = (t2 as? JeAbstractType)?.psiType ?: return false
+
+ return TypeConversionUtil.isAssignable(psiType2, psiType1, false)
+ }
+
+ override fun isSameType(t1: TypeMirror, t2: TypeMirror) = t1 == t2
+
+ override fun getNoType(kind: TypeKind) = CustomJeNoneType(kind)
+
+ override fun getDeclaredType(typeElem: TypeElement, vararg typeArgMirrors: TypeMirror): DeclaredType {
+ val psiClass = (typeElem as JeTypeElement).psi
+ if (!psiClass.hasTypeParameters() && typeArgMirrors.size > 0) {
+ throw IllegalArgumentException("$typeElem has not type parameters")
+ }
+
+ // Raw type
+ if (psiClass.hasTypeParameters() && typeArgMirrors.isEmpty()) {
+ return JeDeclaredType(PsiTypesUtil.getClassType(psiClass).rawType(), psiClass)
+ }
+
+ val typeParameters = psiClass.typeParameters
+ if (typeArgMirrors.size != typeParameters.size) {
+ throw IllegalArgumentException("$typeElem type parameters count: " +
+ "${typeParameters.size}, received ${typeArgMirrors.size} args")
+ }
+
+ val typeArgs = typeArgMirrors.mapIndexed {
+ i, t -> (t as? JeAbstractType)?.psiType ?: throw IllegalArgumentException("Invalid type argument #$i: $t")
+ }
+
+ return JeCompoundDeclaredType(psiClass, typeElem, null, typeArgs, typeArgMirrors.toList())
+ }
+
+ override fun getDeclaredType(
+ containing: DeclaredType?,
+ typeElem: TypeElement,
+ vararg typeArgMirrors: TypeMirror
+ ): DeclaredType? {
+ if (containing == null) {
+ return getDeclaredType(typeElem, *typeArgMirrors)
+ }
+
+ val psiClass = (typeElem as JeTypeElement).psi
+ if (psiClass.containingClass == null) {
+ throw IllegalArgumentException("$typeElem is a top-level class element")
+ }
+
+ val containingType = (containing as? JeAbstractType)?.psiType as? PsiClassType
+ ?: throw IllegalArgumentException("Illegal containing type: $containing")
+ val containingClass = containingType.resolve()
+ ?: throw IllegalArgumentException("Class type can't be resolved: $containing")
+
+ if (psiClass.containingClass != containingClass) {
+ throw IllegalArgumentException("$containing is not an enclosing element for $typeElem")
+ }
+
+ val typeArgs = typeArgMirrors.mapIndexed {
+ i, t -> (t as? JeAbstractType)?.psiType ?: throw IllegalArgumentException("Invalid type argument #$i: $t")
+ }
+
+ return JeCompoundDeclaredType(psiClass, typeElem, containing, typeArgs, typeArgMirrors.toList())
+ }
+
+ override fun asMemberOf(containing: DeclaredType, element: Element): TypeMirror {
+ val substitutor = when (containing) {
+ is JeDeclaredType -> {
+ val result = containing.psiType.resolveGenerics()
+ if (result.isValidResult) result.substitutor else PsiSubstitutor.EMPTY
+ }
+ is JeCompoundDeclaredType -> {
+ val mapping = containing.psiClass.typeParameters.zip(containing.typeArgs).toMap()
+ PsiSubstitutorImpl.createSubstitutor(mapping)
+ }
+ else -> throw IllegalArgumentException("Invalid containing type: $containing")
+ }
+
+ return when (element) {
+ is JeMethodExecutableElement -> {
+ val method = element.psi
+ if (method.hasModifierProperty(PsiModifier.STATIC) || !method.hasTypeParameters()) {
+ JeMethodExecutableTypeMirror(method)
+ } else {
+ val signature = method.getSignature(substitutor)
+ val returnType = substitutor.substitute(element.psi.returnType)
+ JeMethodExecutableTypeMirror(method, signature, returnType)
+ }
+ }
+ is JeClassInitializerExecutableElement -> element.asType()
+ is JeVariableElement -> substitutor.substitute(element.psi.type).toJeType()
+ else -> throw IllegalArgumentException("Invalid element type: $element")
+ }
+ }
+
+ override fun isSubsignature(t1: ExecutableType, t2: ExecutableType): Boolean {
+ val m1 = (t1 as JeClassInitializerExecutableTypeMirror).initializer
+ val m2 = (t2 as JeClassInitializerExecutableTypeMirror).initializer
+
+ if (m1 !is PsiMethod || m2 !is PsiMethod) return false
+ if (m1.parameterList.parametersCount != m2.parameterList.parametersCount) return false
+
+ for (i in 0..(m1.parameterList.parametersCount - 1)) {
+ val p1 = m1.parameterList.parameters[i]
+ val p2 = m2.parameterList.parameters[i]
+
+ if (!TypeConversionUtil.isAssignable(p2.type, p1.type, false)) {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ override fun capture(t: TypeMirror): TypeMirror? {
+ TODO()
+ }
+}
\ No newline at end of file