diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java index 197f1321b19..a418738f581 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/CLICompiler.java @@ -152,6 +152,9 @@ public abstract class CLICompiler { 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 { return INTERNAL_ERROR; } } + + public static class CompilationInterruptedException extends RuntimeException { + final ExitCode exitCode; + + public CompilationInterruptedException(ExitCode exitCode) { + this.exitCode = exitCode; + } + } } diff --git a/plugins/annotation-collector/annotation-collector.iml b/plugins/annotation-collector/annotation-collector.iml index 5d5a86f5f27..27a9e081763 100644 --- a/plugins/annotation-collector/annotation-collector.iml +++ b/plugins/annotation-collector/annotation-collector.iml @@ -14,7 +14,8 @@ - + + \ No newline at end of file diff --git a/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/AnnotationCollectorPlugin.kt b/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/AnnotationCollectorPlugin.kt index 482dc6bd936..8043e90d8bb 100644 --- a/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/AnnotationCollectorPlugin.kt +++ b/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/AnnotationCollectorPlugin.kt @@ -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> = CompilerConfigurationKey.create>("annotation filter regular expressions") public val OUTPUT_FILENAME: CompilerConfigurationKey = - CompilerConfigurationKey.create("output file") + CompilerConfigurationKey.create("annotation file name") + public val STUBS_PATH: CompilerConfigurationKey = + CompilerConfigurationKey.create("stubs output directory") } public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor { @@ -59,11 +62,14 @@ public class AnnotationCollectorCommandLineProcessor : CommandLineProcessor { public val OUTPUT_FILENAME_OPTION: CliOption = CliOption("output", "", "File in which annotated declarations will be placed", required = false) + + public val STUBS_PATH_OPTION: CliOption = + CliOption("stubs", "", "Output path for stubs.", required = false) } override val pluginId: String = ANNOTATION_COLLECTOR_COMPILER_PLUGIN_ID - override val pluginOptions: Collection = listOf(ANNOTATION_FILTER_LIST_OPTION, OUTPUT_FILENAME_OPTION) + override val pluginOptions: Collection = 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))) + } } } diff --git a/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/StubProducerExtension.kt b/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/StubProducerExtension.kt new file mode 100644 index 00000000000..83858117f99 --- /dev/null +++ b/plugins/annotation-collector/src/org/jetbrains/kotlin/annotation/StubProducerExtension.kt @@ -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) { + 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() { + + } +} \ No newline at end of file