kapt: Light class stub producer in compiler

This commit is contained in:
Yan Zhulanow
2015-05-28 20:16:43 +03:00
parent 571c9073fa
commit fbb8d28120
4 changed files with 111 additions and 4 deletions
@@ -152,6 +152,9 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
Disposer.dispose(rootDisposable);
}
}
catch (CompilationInterruptedException e) {
return e.exitCode;
}
catch (Throwable t) {
groupingCollector.report(CompilerMessageSeverity.EXCEPTION, OutputMessageUtil.renderException(t),
CompilerMessageLocation.NO_LOCATION);
@@ -201,4 +204,12 @@ public abstract class CLICompiler<A extends CommonCompilerArguments> {
return INTERNAL_ERROR;
}
}
public static class CompilationInterruptedException extends RuntimeException {
final ExitCode exitCode;
public CompilationInterruptedException(ExitCode exitCode) {
this.exitCode = exitCode;
}
}
}
@@ -14,7 +14,8 @@
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="compiler-tests" scope="TEST" />
<orderEntry type="module" module-name="cli" scope="TEST" />
<orderEntry type="module" module-name="cli" />
<orderEntry type="library" scope="TEST" name="idea-full" level="project" />
<orderEntry type="module" module-name="light-classes" />
</component>
</module>
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetCallableDeclaration
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
import java.io.BufferedWriter
import java.io.File
import java.io.IOException
@@ -47,7 +48,9 @@ public object AnnotationCollectorConfigurationKeys {
public val ANNOTATION_FILTER_LIST: CompilerConfigurationKey<List<String>> =
CompilerConfigurationKey.create<List<String>>("annotation filter regular expressions")
public val OUTPUT_FILENAME: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("output file")
CompilerConfigurationKey.create<String>("annotation file name")
public val STUBS_PATH: CompilerConfigurationKey<String> =
CompilerConfigurationKey.create<String>("stubs output directory")
}
public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
@@ -59,11 +62,14 @@ public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
public val OUTPUT_FILENAME_OPTION: CliOption =
CliOption("output", "<path>", "File in which annotated declarations will be placed", required = false)
public val STUBS_PATH_OPTION: CliOption =
CliOption("stubs", "<path>", "Output path for stubs.", required = false)
}
override val pluginId: String = ANNOTATION_COLLECTOR_COMPILER_PLUGIN_ID
override val pluginOptions: Collection<CliOption> = listOf(ANNOTATION_FILTER_LIST_OPTION, OUTPUT_FILENAME_OPTION)
override val pluginOptions: Collection<CliOption> = listOf(ANNOTATION_FILTER_LIST_OPTION, OUTPUT_FILENAME_OPTION, STUBS_PATH_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) {
when (option) {
@@ -72,6 +78,7 @@ public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor {
configuration.put(AnnotationCollectorConfigurationKeys.ANNOTATION_FILTER_LIST, annotations)
}
OUTPUT_FILENAME_OPTION -> configuration.put(AnnotationCollectorConfigurationKeys.OUTPUT_FILENAME, value)
STUBS_PATH_OPTION -> configuration.put(AnnotationCollectorConfigurationKeys.STUBS_PATH, value)
else -> throw CliOptionProcessingException("Unknown option: ${option.name}")
}
}
@@ -81,11 +88,15 @@ public class AnnotationCollectorComponentRegistrar : ComponentRegistrar {
public override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
val annotationFilterList = configuration.get(AnnotationCollectorConfigurationKeys.ANNOTATION_FILTER_LIST)
val outputFilename = configuration.get(AnnotationCollectorConfigurationKeys.OUTPUT_FILENAME)
if (outputFilename != null) {
val collectorExtension = AnnotationCollectorExtension(annotationFilterList, outputFilename)
ClassBuilderInterceptorExtension.registerExtension(project, collectorExtension)
}
val stubs = configuration.get(AnnotationCollectorConfigurationKeys.STUBS_PATH)
if (stubs != null) {
AnalysisCompletedHandlerExtension.registerExtension(project, StubProducerExtension(File(stubs)))
}
}
}
@@ -0,0 +1,84 @@
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAllTo
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.Progress
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisCompletedHandlerExtension
import org.jetbrains.org.objectweb.asm.ClassWriter
import java.io.File
public class StubProducerExtension(val stubsOutputDir: File) : AnalysisCompletedHandlerExtension {
override fun analysisCompleted(project: Project, module: ModuleDescriptor, bindingContext: BindingContext, files: Collection<JetFile>) {
val forExtraDiagnostics = BindingTraceContext()
val generationState = GenerationState(
project,
StubClassBuilderFactory(),
Progress.DEAF,
module,
bindingContext,
files.toArrayList(),
/*disableCallAssertions =*/ false,
/*disableParamAssertions =*/ false,
GenerationState.GenerateClassFilter.GENERATE_ALL,
/*disableInline =*/ false,
/*disableOptimization =*/ false,
/*packagesWithObsoleteParts =*/ null,
/*moduleId =*/ null,
forExtraDiagnostics,
/*outDirectory =*/ null)
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
if (!stubsOutputDir.exists()) stubsOutputDir.mkdirs()
generationState.getFactory().writeAllTo(stubsOutputDir)
generationState.destroy()
throw CLICompiler.CompilationInterruptedException(ExitCode.OK)
}
}
private class StubClassBuilderFactory : ClassBuilderFactory {
override fun getClassBuilderMode() = ClassBuilderMode.LIGHT_CLASSES
override fun newClassBuilder(origin: JvmDeclarationOrigin) = AbstractClassBuilder.Concrete(
ClassWriter(ClassWriter.COMPUTE_FRAMES or ClassWriter.COMPUTE_MAXS))
override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException("BINARIES generator asked for text")
override fun asBytes(builder: ClassBuilder): ByteArray {
val visitor = builder.getVisitor() as ClassWriter
return visitor.toByteArray()
}
override fun close() {
}
}