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
+24
-5
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.annotation
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
@@ -35,8 +36,10 @@ import java.util.*
|
||||
import javax.annotation.processing.Processor
|
||||
|
||||
class AnnotationProcessingExtension(
|
||||
val generatedOutputDir: File,
|
||||
val annotationProcessingClasspath: List<String>
|
||||
val generatedSourcesOutputDir: File,
|
||||
val classesOutputDir: File,
|
||||
val annotationProcessingClasspath: List<String>,
|
||||
val javaSourceRoots: List<File>
|
||||
) : AnalysisCompletedHandlerExtension {
|
||||
private var annotationProcessingComplete = false
|
||||
|
||||
@@ -56,12 +59,25 @@ class AnnotationProcessingExtension(
|
||||
val analysisContext = AnalysisContext(hashMapOf())
|
||||
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 javaPsiFacade = JavaPsiFacade.getInstance(project)
|
||||
val projectScope = GlobalSearchScope.projectScope(project)
|
||||
|
||||
val filer = KotlinFiler(generatedOutputDir)
|
||||
val filer = KotlinFiler(generatedSourcesOutputDir, classesOutputDir)
|
||||
val messages = KotlinMessager()
|
||||
val types = KotlinTypes(javaPsiFacade, PsiManager.getInstance(project), projectScope)
|
||||
val elements = KotlinElements(javaPsiFacade, projectScope)
|
||||
@@ -69,7 +85,6 @@ class AnnotationProcessingExtension(
|
||||
val processingEnvironment = KotlinProcessingEnvironment(elements, types, messages, options, filer)
|
||||
processors.forEach { it.init(processingEnvironment) }
|
||||
|
||||
|
||||
// Round 1
|
||||
val round1Environment = KotlinRoundEnvironment(analysisContext)
|
||||
for (processor in processors) {
|
||||
@@ -97,7 +112,7 @@ class AnnotationProcessingExtension(
|
||||
}
|
||||
|
||||
annotationProcessingComplete = true
|
||||
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedOutputDir))
|
||||
return AnalysisResult.RetryWithAdditionalJavaRoots(bindingContext, module, listOf(generatedSourcesOutputDir))
|
||||
}
|
||||
|
||||
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) {
|
||||
if (declaration !is PsiModifierListOwner) return
|
||||
|
||||
|
||||
+17
-2
@@ -18,18 +18,23 @@ package org.jetbrains.kotlin.annotation.processing
|
||||
|
||||
import com.intellij.mock.MockProject
|
||||
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.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.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
|
||||
import java.io.File
|
||||
|
||||
object AnnotationProcessingConfigurationKeys {
|
||||
val GENERATED_OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||
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>> =
|
||||
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 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 =
|
||||
CliOption("apclasspath", "<classpath>", "Annotation processor classpath",
|
||||
@@ -60,6 +68,7 @@ class AnnotationProcessingCommandLineProcessor : CommandLineProcessor {
|
||||
configuration.put(AnnotationProcessingConfigurationKeys.ANNOTATION_PROCESSOR_CLASSPATH, paths)
|
||||
}
|
||||
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}")
|
||||
}
|
||||
}
|
||||
@@ -73,7 +82,13 @@ class AnnotationProcessingComponentRegistrar : ComponentRegistrar {
|
||||
val generatedOutputDirFile = File(generatedOutputDir)
|
||||
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)
|
||||
}
|
||||
}
|
||||
+17
-5
@@ -22,8 +22,9 @@ import javax.lang.model.element.Element
|
||||
import javax.tools.FileObject
|
||||
import javax.tools.JavaFileManager
|
||||
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 {
|
||||
val PACKAGE_INFO_SUFFIX = ".packageInfo"
|
||||
}
|
||||
@@ -33,7 +34,7 @@ class KotlinFiler(val generatedDir: File) : Filer {
|
||||
private fun createDotGeneratedIfNeeded() {
|
||||
if (!dotGeneratedGenerated) {
|
||||
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 packageDir = File(generatedDir, packageName.replace('.', '/'))
|
||||
val packageDir = File(generatedSourceDir, packageName.replace('.', '/'))
|
||||
packageDir.mkdirs()
|
||||
|
||||
val fileName = fqName.substringAfterLast('.') + (if (isPackageInfo) PACKAGE_INFO_SUFFIX else extension)
|
||||
@@ -62,12 +63,23 @@ class KotlinFiler(val generatedDir: File) : Filer {
|
||||
}
|
||||
|
||||
override fun createResource(
|
||||
location: JavaFileManager.Location?,
|
||||
location: JavaFileManager.Location,
|
||||
pkg: CharSequence,
|
||||
relativeName: CharSequence,
|
||||
vararg originatingElements: Element?
|
||||
): 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 {
|
||||
|
||||
+22
-17
@@ -17,9 +17,30 @@
|
||||
package org.jetbrains.kotlin.annotation.processing.impl
|
||||
|
||||
import java.io.File
|
||||
import javax.tools.FileObject
|
||||
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 getName() = file.name
|
||||
@@ -39,20 +60,4 @@ class KotlinJavaFileObject(val file: File) : JavaFileObject {
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user