Kapt: Support Java source root processing.
Support resource file writing. (cherry picked from commit 7a06a91)
This commit is contained in:
committed by
Yan Zhulanow
parent
9d2144f221
commit
5b8e6abdeb
@@ -14,5 +14,6 @@
|
|||||||
<orderEntry type="module" module-name="light-classes" />
|
<orderEntry type="module" module-name="light-classes" />
|
||||||
<orderEntry type="module" module-name="util" />
|
<orderEntry type="module" module-name="util" />
|
||||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||||
|
<orderEntry type="module" module-name="cli" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
+24
-5
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.annotation
|
package org.jetbrains.kotlin.annotation
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.vfs.StandardFileSystems
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
@@ -35,8 +36,10 @@ import java.util.*
|
|||||||
import javax.annotation.processing.Processor
|
import javax.annotation.processing.Processor
|
||||||
|
|
||||||
class AnnotationProcessingExtension(
|
class AnnotationProcessingExtension(
|
||||||
val generatedOutputDir: File,
|
val generatedSourcesOutputDir: File,
|
||||||
val annotationProcessingClasspath: List<String>
|
val classesOutputDir: File,
|
||||||
|
val annotationProcessingClasspath: List<String>,
|
||||||
|
val javaSourceRoots: List<File>
|
||||||
) : AnalysisCompletedHandlerExtension {
|
) : AnalysisCompletedHandlerExtension {
|
||||||
private var annotationProcessingComplete = false
|
private var annotationProcessingComplete = false
|
||||||
|
|
||||||
@@ -56,12 +59,25 @@ class AnnotationProcessingExtension(
|
|||||||
val analysisContext = AnalysisContext(hashMapOf())
|
val analysisContext = AnalysisContext(hashMapOf())
|
||||||
analysisContext.analyzeFiles(files)
|
analysisContext.analyzeFiles(files)
|
||||||
|
|
||||||
|
val psiManager = PsiManager.getInstance(project)
|
||||||
|
for (javaSourceRoot in javaSourceRoots) {
|
||||||
|
javaSourceRoot.walk().filter { it.isFile && it.extension == "java" }.forEach {
|
||||||
|
val vFile = StandardFileSystems.local().findFileByPath(it.absolutePath)
|
||||||
|
if (vFile != null) {
|
||||||
|
val javaFile = psiManager.findFile(vFile) as? PsiJavaFile
|
||||||
|
if (javaFile != null) {
|
||||||
|
analysisContext.analyzeFile(javaFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val options = emptyMap<String, String>()
|
val options = emptyMap<String, String>()
|
||||||
|
|
||||||
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
val javaPsiFacade = JavaPsiFacade.getInstance(project)
|
||||||
val projectScope = GlobalSearchScope.projectScope(project)
|
val projectScope = GlobalSearchScope.projectScope(project)
|
||||||
|
|
||||||
val filer = KotlinFiler(generatedOutputDir)
|
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
||||||
val messages = KotlinMessager()
|
val messages = KotlinMessager()
|
||||||
val types = KotlinTypes(javaPsiFacade, PsiManager.getInstance(project), projectScope)
|
val types = KotlinTypes(javaPsiFacade, PsiManager.getInstance(project), projectScope)
|
||||||
val elements = KotlinElements(javaPsiFacade, projectScope)
|
val elements = KotlinElements(javaPsiFacade, projectScope)
|
||||||
@@ -69,7 +85,6 @@ class AnnotationProcessingExtension(
|
|||||||
val processingEnvironment = KotlinProcessingEnvironment(elements, types, messages, options, filer)
|
val processingEnvironment = KotlinProcessingEnvironment(elements, types, messages, options, filer)
|
||||||
processors.forEach { it.init(processingEnvironment) }
|
processors.forEach { it.init(processingEnvironment) }
|
||||||
|
|
||||||
|
|
||||||
// Round 1
|
// Round 1
|
||||||
val round1Environment = KotlinRoundEnvironment(analysisContext)
|
val round1Environment = KotlinRoundEnvironment(analysisContext)
|
||||||
for (processor in processors) {
|
for (processor in processors) {
|
||||||
@@ -97,7 +112,7 @@ class AnnotationProcessingExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
annotationProcessingComplete = true
|
annotationProcessingComplete = true
|
||||||
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedOutputDir))
|
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedSourcesOutputDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAnnotationProcessors(classpath: List<String>): List<Processor> {
|
private fun loadAnnotationProcessors(classpath: List<String>): List<Processor> {
|
||||||
@@ -128,6 +143,10 @@ private fun AnalysisContext.analyzeFile(file: KtFile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun AnalysisContext.analyzeFile(file: PsiJavaFile) {
|
||||||
|
file.classes.forEach { analyzeDeclaration(it) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun AnalysisContext.analyzeDeclaration(declaration: PsiElement) {
|
private fun AnalysisContext.analyzeDeclaration(declaration: PsiElement) {
|
||||||
if (declaration !is PsiModifierListOwner) return
|
if (declaration !is PsiModifierListOwner) return
|
||||||
|
|
||||||
|
|||||||
+17
-2
@@ -18,12 +18,14 @@ package org.jetbrains.kotlin.annotation.processing
|
|||||||
|
|
||||||
import com.intellij.mock.MockProject
|
import com.intellij.mock.MockProject
|
||||||
import org.jetbrains.kotlin.annotation.AnnotationProcessingExtension
|
import org.jetbrains.kotlin.annotation.AnnotationProcessingExtension
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
|
||||||
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
import org.jetbrains.kotlin.compiler.plugin.CliOption
|
||||||
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
import org.jetbrains.kotlin.compiler.plugin.CliOptionProcessingException
|
||||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||||
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -31,6 +33,9 @@ object AnnotationProcessingConfigurationKeys {
|
|||||||
val GENERATED_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
val GENERATED_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||||
CompilerConfigurationKey.create<String>("generated files output directory")
|
CompilerConfigurationKey.create<String>("generated files output directory")
|
||||||
|
|
||||||
|
val CLASS_FILES_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||||
|
CompilerConfigurationKey.create<String>("class files output directory")
|
||||||
|
|
||||||
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
val ANNOTATION_PROCESSOR_CLASSPATH: CompilerConfigurationKey<List<String>> =
|
||||||
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
CompilerConfigurationKey.create<List<String>>("annotation processor classpath")
|
||||||
}
|
}
|
||||||
@@ -40,7 +45,10 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt2"
|
val ANNOTATION_PROCESSING_COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.kapt2"
|
||||||
|
|
||||||
val GENERATED_OUTPUT_DIR_OPTION: CliOption =
|
val GENERATED_OUTPUT_DIR_OPTION: CliOption =
|
||||||
CliOption("generated", "<path>", "Output path for generated files", required = false)
|
CliOption("generated", "<path>", "Output path for the generated files", required = false)
|
||||||
|
|
||||||
|
val CLASS_FILES_OUTPUT_DIR_OPTION: CliOption =
|
||||||
|
CliOption("classes", "<path>", "Output path for the class files", required = false)
|
||||||
|
|
||||||
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
|
val ANNOTATION_PROCESSOR_CLASSPATH_OPTION: CliOption =
|
||||||
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
||||||
@@ -60,6 +68,7 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
|||||||
configuration.put(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH, paths)
|
configuration.put(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH, paths)
|
||||||
}
|
}
|
||||||
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
|
GENERATED_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.GENERATED_OUTPUT_DIR, value)
|
||||||
|
CLASS_FILES_OUTPUT_DIR_OPTION -> configuration.put(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR, value)
|
||||||
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +82,13 @@ class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
|||||||
val generatedOutputDirFile = File(generatedOutputDir)
|
val generatedOutputDirFile = File(generatedOutputDir)
|
||||||
generatedOutputDirFile.mkdirs()
|
generatedOutputDirFile.mkdirs()
|
||||||
|
|
||||||
val annotationProcessingExtension = AnnotationProcessingExtension(generatedOutputDirFile, classpath)
|
val javaRoots = configuration[JVMConfigurationKeys.CONTENT_ROOTS]
|
||||||
|
?.filterIsInstance<JavaSourceRoot>()?.map { it.file } ?: emptyList()
|
||||||
|
|
||||||
|
val classesOutputDir = File(configuration.get(AnnotationProcessingConfigurationKeys.CLASS_FILES_OUTPUT_DIR)
|
||||||
|
?: configuration[JVMConfigurationKeys.MODULES]!!.first().getOutputDirectory())
|
||||||
|
|
||||||
|
val annotationProcessingExtension = AnnotationProcessingExtension(generatedOutputDirFile, classesOutputDir, classpath, javaRoots)
|
||||||
AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
|
AnalysisCompletedHandlerExtension.registerExtension(project, annotationProcessingExtension)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+17
-5
@@ -22,8 +22,9 @@ import javax.lang.model.element.Element
|
|||||||
import javax.tools.FileObject
|
import javax.tools.FileObject
|
||||||
import javax.tools.JavaFileManager
|
import javax.tools.JavaFileManager
|
||||||
import javax.tools.JavaFileObject
|
import javax.tools.JavaFileObject
|
||||||
|
import javax.tools.StandardLocation
|
||||||
|
|
||||||
class KotlinFiler(val generatedDir: File) : Filer {
|
class KotlinFiler(val generatedSourceDir: File, val classesOutputDir: File) : Filer {
|
||||||
private companion object {
|
private companion object {
|
||||||
val PACKAGE_INFO_SUFFIX = ".packageInfo"
|
val PACKAGE_INFO_SUFFIX = ".packageInfo"
|
||||||
}
|
}
|
||||||
@@ -33,7 +34,7 @@ class KotlinFiler(val generatedDir: File) : Filer {
|
|||||||
private fun createDotGeneratedIfNeeded() {
|
private fun createDotGeneratedIfNeeded() {
|
||||||
if (!dotGeneratedGenerated) {
|
if (!dotGeneratedGenerated) {
|
||||||
dotGeneratedGenerated = true
|
dotGeneratedGenerated = true
|
||||||
File(generatedDir, ".generated").writeText("Generated by kapt2")
|
File(generatedSourceDir, ".generated").writeText("Generated by kapt2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ class KotlinFiler(val generatedDir: File) : Filer {
|
|||||||
|
|
||||||
val packageName = fqName.substringBeforeLast('.')
|
val packageName = fqName.substringBeforeLast('.')
|
||||||
|
|
||||||
val packageDir = File(generatedDir, packageName.replace('.', '/'))
|
val packageDir = File(generatedSourceDir, packageName.replace('.', '/'))
|
||||||
packageDir.mkdirs()
|
packageDir.mkdirs()
|
||||||
|
|
||||||
val fileName = fqName.substringAfterLast('.') + (if (isPackageInfo) PACKAGE_INFO_SUFFIX else extension)
|
val fileName = fqName.substringAfterLast('.') + (if (isPackageInfo) PACKAGE_INFO_SUFFIX else extension)
|
||||||
@@ -62,12 +63,23 @@ class KotlinFiler(val generatedDir: File) : Filer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createResource(
|
override fun createResource(
|
||||||
location: JavaFileManager.Location?,
|
location: JavaFileManager.Location,
|
||||||
pkg: CharSequence,
|
pkg: CharSequence,
|
||||||
relativeName: CharSequence,
|
relativeName: CharSequence,
|
||||||
vararg originatingElements: Element?
|
vararg originatingElements: Element?
|
||||||
): FileObject? {
|
): FileObject? {
|
||||||
throw UnsupportedOperationException()
|
val baseDir = when (location) {
|
||||||
|
StandardLocation.CLASS_OUTPUT -> classesOutputDir
|
||||||
|
StandardLocation.SOURCE_OUTPUT -> generatedSourceDir
|
||||||
|
else -> throw IllegalArgumentException("Location is not supported: $location (${location.name})")
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetDir = File(baseDir, pkg.toString().replace('.', '/'))
|
||||||
|
targetDir.mkdirs()
|
||||||
|
|
||||||
|
val targetFile = File(targetDir, relativeName.toString())
|
||||||
|
|
||||||
|
return KotlinFileObject(targetFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createClassFile(name: CharSequence, vararg originatingElements: Element?): JavaFileObject {
|
override fun createClassFile(name: CharSequence, vararg originatingElements: Element?): JavaFileObject {
|
||||||
|
|||||||
+22
-17
@@ -17,9 +17,30 @@
|
|||||||
package org.jetbrains.kotlin.annotation.processing.impl
|
package org.jetbrains.kotlin.annotation.processing.impl
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import javax.tools.FileObject
|
||||||
import javax.tools.JavaFileObject
|
import javax.tools.JavaFileObject
|
||||||
|
|
||||||
class KotlinJavaFileObject(val file: File) : JavaFileObject {
|
class KotlinJavaFileObject(file: File) : KotlinAbstractFileObject(file), JavaFileObject {
|
||||||
|
//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
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinFileObject(file: File) : KotlinAbstractFileObject(file)
|
||||||
|
|
||||||
|
abstract class KotlinAbstractFileObject(val file: File) : FileObject {
|
||||||
override fun openOutputStream() = file.outputStream()
|
override fun openOutputStream() = file.outputStream()
|
||||||
|
|
||||||
override fun getName() = file.name
|
override fun getName() = file.name
|
||||||
@@ -39,20 +60,4 @@ class KotlinJavaFileObject(val file: File) : JavaFileObject {
|
|||||||
override fun openReader(ignoreEncodingErrors: Boolean) = file.reader()
|
override fun openReader(ignoreEncodingErrors: Boolean) = file.reader()
|
||||||
|
|
||||||
override fun delete() = file.delete()
|
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
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user