JVM: New single-pass implementation for jvm-abi-gen
This commit is contained in:
committed by
Alexander Udalov
parent
a54503cede
commit
d08990ebb4
@@ -50,6 +50,7 @@ dependencies {
|
||||
testCompile(protobufCompareSourceSet.output)
|
||||
|
||||
testCompile(projectTests(":compiler:cli"))
|
||||
testCompile(projectTests(":compiler:incremental-compilation-impl"))
|
||||
testCompile(projectTests(":plugins:jvm-abi-gen"))
|
||||
testCompile(projectTests(":plugins:android-extensions-compiler"))
|
||||
testCompile(projectTests(":plugins:parcelize:parcelize-compiler"))
|
||||
|
||||
@@ -19,9 +19,7 @@ import org.jetbrains.kotlin.fir.plugin.AbstractFirAllOpenDiagnosticTest
|
||||
import org.jetbrains.kotlin.generators.TestGroup
|
||||
import org.jetbrains.kotlin.generators.impl.generateTestGroupSuite
|
||||
import org.jetbrains.kotlin.incremental.*
|
||||
import org.jetbrains.kotlin.jvm.abi.AbstractCompareJvmAbiTest
|
||||
import org.jetbrains.kotlin.jvm.abi.AbstractCompileAgainstJvmAbiTest
|
||||
import org.jetbrains.kotlin.jvm.abi.AbstractJvmAbiContentTest
|
||||
import org.jetbrains.kotlin.jvm.abi.*
|
||||
import org.jetbrains.kotlin.kapt.cli.test.AbstractArgumentParsingTest
|
||||
import org.jetbrains.kotlin.kapt.cli.test.AbstractKaptToolIntegrationTest
|
||||
import org.jetbrains.kotlin.kapt3.test.AbstractClassFileToSourceStubConverterTest
|
||||
@@ -169,15 +167,45 @@ fun main(args: Array<String>) {
|
||||
|
||||
testGroup("plugins/jvm-abi-gen/test", "plugins/jvm-abi-gen/testData") {
|
||||
testClass<AbstractCompareJvmAbiTest> {
|
||||
model("compare", recursive = false, extension = null)
|
||||
model("compare", recursive = false, extension = null, targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractJvmAbiContentTest> {
|
||||
model("content", recursive = false, extension = null)
|
||||
model("content", recursive = false, extension = null, targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractCompileAgainstJvmAbiTest> {
|
||||
model("compile", recursive = false, extension = null)
|
||||
model("compile", recursive = false, extension = null, targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractIrCompareJvmAbiTest> {
|
||||
model("compare", recursive = false, extension = null, targetBackend = TargetBackend.JVM_IR)
|
||||
}
|
||||
|
||||
testClass<AbstractIrJvmAbiContentTest> {
|
||||
model("content", recursive = false, extension = null, targetBackend = TargetBackend.JVM_IR)
|
||||
}
|
||||
|
||||
testClass<AbstractIrCompileAgainstJvmAbiTest> {
|
||||
model("compile", recursive = false, extension = null, targetBackend = TargetBackend.JVM_IR)
|
||||
}
|
||||
}
|
||||
|
||||
testGroup(
|
||||
"plugins/jvm-abi-gen/test", "plugins/jvm-abi-gen/testData",
|
||||
testRunnerMethodName = "runTestWithCustomIgnoreDirective",
|
||||
additionalRunnerArguments = listOf("\"// IGNORE_BACKEND_LEGACY: \"")
|
||||
) {
|
||||
testClass<AbstractLegacyCompareJvmAbiTest> {
|
||||
model("compare", recursive = false, extension = null, targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractLegacyJvmAbiContentTest> {
|
||||
model("content", recursive = false, extension = null, targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractLegacyCompileAgainstJvmAbiTest> {
|
||||
model("compile", recursive = false, extension = null, targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
description = "ABI generation for Kotlin/JVM"
|
||||
|
||||
@@ -6,7 +7,16 @@ plugins {
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
val shadows: Configuration by configurations.creating {
|
||||
isTransitive = false
|
||||
}
|
||||
configurations.getByName("compileOnly").extendsFrom(shadows)
|
||||
configurations.getByName("testCompile").extendsFrom(shadows)
|
||||
|
||||
dependencies {
|
||||
// Should come before compiler dependencies, see comment in "compiler/build.gradle.kts"
|
||||
testRuntimeOnly(intellijDep())
|
||||
|
||||
compileOnly(project(":compiler:util"))
|
||||
compileOnly(project(":compiler:cli"))
|
||||
compileOnly(project(":compiler:backend"))
|
||||
@@ -15,14 +25,19 @@ dependencies {
|
||||
compileOnly(project(":compiler:plugin-api"))
|
||||
compileOnly(project(":kotlin-build-common"))
|
||||
|
||||
// Include kotlinx.metadata for metadata stripping.
|
||||
// Note that kotlinx-metadata-jvm already includes kotlinx-metadata, core:metadata, core:metadata.jvm,
|
||||
// and protobuf-lite, so we only need to include kotlinx-metadata-jvm in the shadow jar.
|
||||
compileOnly(project(":kotlinx-metadata"))
|
||||
shadows(project(":kotlinx-metadata-jvm"))
|
||||
|
||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "asm-all", rootProject = rootProject) }
|
||||
|
||||
testRuntimeOnly(project(":kotlin-compiler"))
|
||||
|
||||
testCompile(commonDep("junit:junit"))
|
||||
testCompile(projectTests(":compiler:tests-common"))
|
||||
testCompile(projectTests(":compiler:incremental-compilation-impl"))
|
||||
testRuntime(intellijCoreDep())
|
||||
testImplementation(commonDep("junit:junit"))
|
||||
testImplementation(projectTests(":compiler:tests-common"))
|
||||
testImplementation(projectTests(":compiler:incremental-compilation-impl"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
@@ -30,6 +45,20 @@ sourceSets {
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
noDefaultJar()
|
||||
runtimeJar(tasks.register<ShadowJar>("shadowJar")) {
|
||||
callGroovy("manifestAttributes", manifest, project)
|
||||
manifest.attributes["Implementation-Version"] = archiveVersion
|
||||
|
||||
from(mainSourceSet.output)
|
||||
configurations = listOf(shadows)
|
||||
relocate("kotlinx.metadata", "org.jetbrains.kotlin.jvm.abi.kotlinx.metadata")
|
||||
mergeServiceFiles() // This is needed to relocate the services files for kotlinx.metadata
|
||||
}
|
||||
|
||||
val test by tasks
|
||||
test.dependsOn("shadowJar")
|
||||
|
||||
projectTest(parallel = true) {
|
||||
workingDir = rootDir
|
||||
dependsOn(":dist")
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.DelegatingClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
enum class AbiMethodInfo {
|
||||
KEEP,
|
||||
STRIP,
|
||||
}
|
||||
|
||||
sealed class AbiClassInfo {
|
||||
object Public : AbiClassInfo()
|
||||
class Stripped(val methodInfo: Map<Method, AbiMethodInfo>) : AbiClassInfo()
|
||||
}
|
||||
|
||||
/**
|
||||
* Record ABI information for all classes in the current compilation unit.
|
||||
*
|
||||
* This needs to be a `ClassBuilderInterceptor`, since we need the descriptors
|
||||
* in order to know which methods can be safely stripped from the output.
|
||||
* On the other hand we cannot produce any output in this pass, since we need
|
||||
* to know which classes are part of the public ABI in order to produce the
|
||||
* correct `InnerClasses` attributes.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Classes which are private, local, or anonymous can be stripped unless
|
||||
* they are marked as part of the public ABI by a bit in the Kotlin
|
||||
* metadata annotation. Public ABI classes have to be kept verbatim, since
|
||||
* they are copied to all call sites of a surrounding inline function.
|
||||
*
|
||||
* If we keep a class we will strip the bodies from all non-inline function,
|
||||
* remove private functions, and copy inline functions verbatim. There is one
|
||||
* exception to this for inline suspend functions.
|
||||
*
|
||||
* For an inline suspend function `f` we will usually generate two methods,
|
||||
* a non-inline method `f` and an inline method `f$$forInline`. The former can
|
||||
* be stripped. However, if `f` is not callable directly, we only generate a
|
||||
* single inline method `f` which should be kept.
|
||||
*/
|
||||
class JvmAbiClassBuilderInterceptor : ClassBuilderInterceptorExtension {
|
||||
val abiClassInfo: MutableMap<String, AbiClassInfo> = mutableMapOf()
|
||||
|
||||
override fun interceptClassBuilderFactory(interceptedFactory: ClassBuilderFactory, bindingContext: BindingContext, diagnostics: DiagnosticSink): ClassBuilderFactory =
|
||||
object : DelegatingClassBuilderFactory(interceptedFactory) {
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): DelegatingClassBuilder =
|
||||
AbiInfoClassBuilder(interceptedFactory.newClassBuilder(origin))
|
||||
}
|
||||
|
||||
private inner class AbiInfoClassBuilder(private val delegate: ClassBuilder) : DelegatingClassBuilder() {
|
||||
lateinit var internalName: String
|
||||
var localOrAnonymousClass = false
|
||||
var publicAbi = false
|
||||
val methodInfos = mutableMapOf<Method, AbiMethodInfo>()
|
||||
val maskedMethods = mutableSetOf<Method>() // Methods which should be stripped even if they are marked as KEEP
|
||||
|
||||
override fun getDelegate(): ClassBuilder = delegate
|
||||
|
||||
override fun defineClass(origin: PsiElement?, version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<out String>) {
|
||||
internalName = name
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces)
|
||||
}
|
||||
|
||||
override fun visitOuterClass(owner: String, name: String?, desc: String?) {
|
||||
localOrAnonymousClass = true
|
||||
super.visitOuterClass(owner, name, desc)
|
||||
}
|
||||
|
||||
override fun newMethod(origin: JvmDeclarationOrigin, access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor {
|
||||
// inline suspend functions are a special case: Unless they use reified type parameters,
|
||||
// we will transform the original method and generate a $$forInline method for the inliner.
|
||||
// Only the latter needs to be kept, the former can be stripped. Unfortunately, there is no
|
||||
// metadata to indicate this (the inliner simply first checks for a method such as `f$$forInline`
|
||||
// and then checks for `f` if this method doesn't exist) so we have to remember to strip the
|
||||
// original methods if there was a $$forInline version.
|
||||
if (name.endsWith(FOR_INLINE_SUFFIX)) {
|
||||
// Note that origin.descriptor is null on the JVM BE in this case.
|
||||
methodInfos[Method(name, desc)] = AbiMethodInfo.KEEP
|
||||
maskedMethods += Method(name.removeSuffix(FOR_INLINE_SUFFIX), desc)
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
|
||||
// Remove private functions from the ABI jars
|
||||
val descriptor = origin.descriptor as? MemberDescriptor
|
||||
if (access and Opcodes.ACC_PRIVATE != 0 && descriptor?.visibility?.let(DescriptorVisibilities::isPrivate) == true
|
||||
|| name == "<clinit>" || name.startsWith("access\$") && access and Opcodes.ACC_SYNTHETIC != 0) {
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
|
||||
// Copy inline functions verbatim
|
||||
if (origin.descriptor?.safeAs<FunctionDescriptor>()?.isInline == true) {
|
||||
methodInfos[Method(name, desc)] = AbiMethodInfo.KEEP
|
||||
} else {
|
||||
methodInfos[Method(name, desc)] = AbiMethodInfo.STRIP
|
||||
}
|
||||
return super.newMethod(origin, access, name, desc, signature, exceptions)
|
||||
}
|
||||
|
||||
// Parse the public ABI flag from the Kotlin metadata annotation
|
||||
override fun newAnnotation(desc: String, visible: Boolean): AnnotationVisitor {
|
||||
val delegate = super.newAnnotation(desc, visible)
|
||||
if (desc != JvmAnnotationNames.METADATA_DESC)
|
||||
return delegate
|
||||
|
||||
return object : AnnotationVisitor(Opcodes.API_VERSION, delegate) {
|
||||
override fun visit(name: String?, value: Any?) {
|
||||
if ((name == JvmAnnotationNames.METADATA_EXTRA_INT_FIELD_NAME) && (value is Int)) {
|
||||
publicAbi = publicAbi || value and JvmAnnotationNames.METADATA_PUBLIC_ABI_FLAG != 0
|
||||
}
|
||||
super.visit(name, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun done() {
|
||||
// Remove local or anonymous classes unless they are in the scope of an inline function and
|
||||
// strip non-inline methods from all other classe.
|
||||
when {
|
||||
publicAbi ->
|
||||
abiClassInfo[internalName] = AbiClassInfo.Public
|
||||
!localOrAnonymousClass -> {
|
||||
for (method in maskedMethods) {
|
||||
methodInfos.replace(method, AbiMethodInfo.STRIP)
|
||||
}
|
||||
abiClassInfo[internalName] = AbiClassInfo.Stripped(methodInfos)
|
||||
}
|
||||
}
|
||||
super.done()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,33 @@ class JvmAbiCommandLineProcessor : CommandLineProcessor {
|
||||
companion object {
|
||||
const val COMPILER_PLUGIN_ID: String = "org.jetbrains.kotlin.jvm.abi"
|
||||
|
||||
val OUTPUT_DIR_OPTION: CliOption =
|
||||
CliOption("outputDir", "<path>", "Output path for the generated files", required = true)
|
||||
val OUTPUT_PATH_OPTION: CliOption =
|
||||
CliOption(
|
||||
"outputDir",
|
||||
"<path>",
|
||||
"Output path for generated files. This can be either a directory or a jar file.",
|
||||
true
|
||||
)
|
||||
|
||||
val LEGACY_ABI_GEN_OPTION: CliOption =
|
||||
CliOption(
|
||||
"useLegacyAbiGen",
|
||||
"true|false",
|
||||
"Use the legacy two pass implementation of jvm-abi-gen.",
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
override val pluginId: String
|
||||
get() = COMPILER_PLUGIN_ID
|
||||
|
||||
override val pluginOptions: Collection<CliOption>
|
||||
get() = listOf(OUTPUT_DIR_OPTION)
|
||||
get() = listOf(OUTPUT_PATH_OPTION, LEGACY_ABI_GEN_OPTION)
|
||||
|
||||
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
||||
when (option) {
|
||||
OUTPUT_DIR_OPTION -> configuration.put(JvmAbiConfigurationKeys.OUTPUT_DIR, value)
|
||||
OUTPUT_PATH_OPTION -> configuration.put(JvmAbiConfigurationKeys.OUTPUT_PATH, value)
|
||||
LEGACY_ABI_GEN_OPTION -> configuration.put(JvmAbiConfigurationKeys.LEGACY_ABI_GEN, value == "true")
|
||||
else -> throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import com.intellij.mock.MockProject
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassFileFactoryFinalizerExtension
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
@@ -14,13 +16,23 @@ import java.io.File
|
||||
|
||||
class JvmAbiComponentRegistrar : ComponentRegistrar {
|
||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val configuration = configuration.copy()
|
||||
configuration.get(JvmAbiConfigurationKeys.OUTPUT_DIR)?.let {
|
||||
val dir = File(it)
|
||||
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, dir)
|
||||
val outputPath = configuration.getNotNull(JvmAbiConfigurationKeys.OUTPUT_PATH)
|
||||
if (configuration.get(JvmAbiConfigurationKeys.LEGACY_ABI_GEN, false)) {
|
||||
// Use the two-pass implementation
|
||||
require(!outputPath.endsWith(".jar")) {
|
||||
"Legacy jvm-abi-gen does not support jar output."
|
||||
}
|
||||
val extension = JvmAbiAnalysisHandlerExtension(configuration.copy().apply {
|
||||
put(JVMConfigurationKeys.OUTPUT_DIRECTORY, File(outputPath))
|
||||
})
|
||||
AnalysisHandlerExtension.registerExtension(project, extension)
|
||||
} else {
|
||||
// Use the single-pass implementation, using the new ABI flag in the metadata.
|
||||
configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
|
||||
val builderExtension = JvmAbiClassBuilderInterceptor()
|
||||
val outputExtension = JvmAbiOutputExtension(File(outputPath), builderExtension.abiClassInfo)
|
||||
ClassBuilderInterceptorExtension.registerExtension(project, builderExtension)
|
||||
ClassFileFactoryFinalizerExtension.registerExtension(project, outputExtension)
|
||||
}
|
||||
val extension = JvmAbiAnalysisHandlerExtension(configuration)
|
||||
AnalysisHandlerExtension.registerExtension(project, extension)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,9 @@ package org.jetbrains.kotlin.jvm.abi
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
|
||||
object JvmAbiConfigurationKeys {
|
||||
val OUTPUT_DIR: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(JvmAbiCommandLineProcessor.OUTPUT_DIR_OPTION.description)
|
||||
val OUTPUT_PATH: CompilerConfigurationKey<String> =
|
||||
CompilerConfigurationKey.create<String>(JvmAbiCommandLineProcessor.OUTPUT_PATH_OPTION.description)
|
||||
|
||||
val LEGACY_ABI_GEN: CompilerConfigurationKey<Boolean> =
|
||||
CompilerConfigurationKey.create<Boolean>(JvmAbiCommandLineProcessor.LEGACY_ABI_GEN_OPTION.description)
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import kotlinx.metadata.*
|
||||
import kotlinx.metadata.jvm.JvmClassExtensionVisitor
|
||||
import kotlinx.metadata.jvm.JvmPackageExtensionVisitor
|
||||
import kotlinx.metadata.jvm.KotlinClassHeader
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.*
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
/**
|
||||
* Wrap the visitor for a Kotlin Metadata annotation to strip out private and local
|
||||
* functions, properties, and type aliases as well as local delegated properties.
|
||||
*/
|
||||
fun abiMetadataProcessor(internalName: String, publicClasses: Set<String>, annotationVisitor: AnnotationVisitor): AnnotationVisitor =
|
||||
kotlinClassHeaderVisitor { header ->
|
||||
val newHeader = when (val metadata = KotlinClassMetadata.read(header)) {
|
||||
is KotlinClassMetadata.Class -> {
|
||||
val writer = KotlinClassMetadata.Class.Writer()
|
||||
metadata.accept(AbiKmClassVisitor(internalName, publicClasses, writer))
|
||||
writer.write(header.metadataVersion, header.extraInt).header
|
||||
}
|
||||
is KotlinClassMetadata.FileFacade -> {
|
||||
val writer = KotlinClassMetadata.FileFacade.Writer()
|
||||
metadata.accept(AbiKmPackageVisitor(writer))
|
||||
writer.write(header.metadataVersion, header.extraInt).header
|
||||
}
|
||||
is KotlinClassMetadata.MultiFileClassPart -> {
|
||||
val writer = KotlinClassMetadata.MultiFileClassPart.Writer()
|
||||
metadata.accept(AbiKmPackageVisitor(writer))
|
||||
writer.write(metadata.facadeClassName, header.metadataVersion, header.extraInt).header
|
||||
}
|
||||
else -> header
|
||||
}
|
||||
|
||||
// Write out the stripped annotation
|
||||
annotationVisitor.visitKotlinMetadata(newHeader)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a KotlinClassHeader from an existing Kotlin Metadata annotation visitor.
|
||||
*/
|
||||
private fun kotlinClassHeaderVisitor(body: (KotlinClassHeader) -> Unit): AnnotationVisitor =
|
||||
object : AnnotationVisitor(Opcodes.API_VERSION) {
|
||||
var kind: Int = 1
|
||||
var metadataVersion: IntArray = intArrayOf()
|
||||
var data1: MutableList<String> = mutableListOf()
|
||||
var data2: MutableList<String> = mutableListOf()
|
||||
var extraString: String = ""
|
||||
var packageName: String = ""
|
||||
var extraInt: Int = 0
|
||||
|
||||
override fun visit(name: String, value: Any?) {
|
||||
when (name) {
|
||||
KIND_FIELD_NAME -> kind = value as Int
|
||||
METADATA_EXTRA_INT_FIELD_NAME -> extraInt = value as Int
|
||||
METADATA_VERSION_FIELD_NAME -> metadataVersion = value as IntArray
|
||||
METADATA_EXTRA_STRING_FIELD_NAME -> extraString = value as String
|
||||
METADATA_PACKAGE_NAME_FIELD_NAME -> packageName = value as String
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitArray(name: String): AnnotationVisitor {
|
||||
val destination = when (name) {
|
||||
METADATA_DATA_FIELD_NAME -> data1
|
||||
METADATA_STRINGS_FIELD_NAME -> data2
|
||||
else -> error("Wrong array field in kotlin metadata: $name")
|
||||
}
|
||||
return object : AnnotationVisitor(Opcodes.ASM7) {
|
||||
override fun visit(name: String?, value: Any?) {
|
||||
destination += value as String
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun visitEnd() {
|
||||
body(KotlinClassHeader(
|
||||
kind,
|
||||
metadataVersion,
|
||||
data1.toTypedArray(),
|
||||
data2.toTypedArray(),
|
||||
extraString,
|
||||
packageName,
|
||||
extraInt
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a KotlinClassHeader to an existing Kotlin Metadata annotation visitor.
|
||||
*/
|
||||
private fun AnnotationVisitor.visitKotlinMetadata(header: KotlinClassHeader) {
|
||||
visit(KIND_FIELD_NAME, header.kind)
|
||||
visit(METADATA_VERSION_FIELD_NAME, header.metadataVersion)
|
||||
visitArray(METADATA_DATA_FIELD_NAME).apply {
|
||||
header.data1.forEach { visit(null, it) }
|
||||
visitEnd()
|
||||
}
|
||||
visitArray(METADATA_STRINGS_FIELD_NAME).apply {
|
||||
header.data2.forEach { visit(null, it) }
|
||||
visitEnd()
|
||||
}
|
||||
visit(METADATA_EXTRA_STRING_FIELD_NAME, header.extraString)
|
||||
visit(METADATA_PACKAGE_NAME_FIELD_NAME, header.packageName)
|
||||
visit(METADATA_EXTRA_INT_FIELD_NAME, header.extraInt)
|
||||
visitEnd()
|
||||
}
|
||||
|
||||
/**
|
||||
* Class metadata adapter which removes private functions, properties, type aliases,
|
||||
* and local delegated properties.
|
||||
*/
|
||||
private class AbiKmClassVisitor(private val internalName: String, private val publicClasses: Set<String>, delegate: KmClassVisitor) : KmClassVisitor(delegate) {
|
||||
override fun visitConstructor(flags: Flags): KmConstructorVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitConstructor(flags)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitFunction(flags, name)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitProperty(flags, name, getterFlags, setterFlags)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitNestedClass(name: String) {
|
||||
if ("$internalName\$$name" in publicClasses)
|
||||
super.visitNestedClass(name)
|
||||
}
|
||||
|
||||
override fun visitCompanionObject(name: String) {
|
||||
if ("$internalName\$$name" in publicClasses)
|
||||
super.visitCompanionObject(name)
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitTypeAlias(flags, name)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? {
|
||||
val delegate = super.visitExtensions(type)
|
||||
if (type != JvmClassExtensionVisitor.TYPE) return delegate
|
||||
return object : JvmClassExtensionVisitor(delegate as JvmClassExtensionVisitor?) {
|
||||
override fun visitLocalDelegatedProperty(
|
||||
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
|
||||
): KmPropertyVisitor? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class metadata adapter which removes private functions, properties, and type aliases.
|
||||
*/
|
||||
private class AbiKmPackageVisitor(delegate: KmPackageVisitor) : KmPackageVisitor(delegate) {
|
||||
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitFunction(flags, name)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitProperty(flags, name, getterFlags, setterFlags)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? {
|
||||
if (!isPrivateDeclaration(flags))
|
||||
return super.visitTypeAlias(flags, name)
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? {
|
||||
val delegate = super.visitExtensions(type)
|
||||
if (type != JvmPackageExtensionVisitor.TYPE) return delegate
|
||||
return object : JvmPackageExtensionVisitor(delegate as JvmPackageExtensionVisitor?) {
|
||||
override fun visitLocalDelegatedProperty(
|
||||
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
|
||||
): KmPropertyVisitor? = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isPrivateDeclaration(flags: Flags): Boolean =
|
||||
Flag.IS_PRIVATE(flags) || Flag.IS_PRIVATE_TO_THIS(flags) || Flag.IS_LOCAL(flags)
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||
import org.jetbrains.kotlin.backend.common.output.SimpleOutputBinaryFile
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.output.writeAllTo
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.CompileEnvironmentUtil
|
||||
import org.jetbrains.kotlin.codegen.ClassFileFactory
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassFileFactoryFinalizerExtension
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import java.io.File
|
||||
|
||||
class JvmAbiOutputExtension(
|
||||
private val outputPath: File,
|
||||
private val abiClassInfos: Map<String, AbiClassInfo>,
|
||||
) : ClassFileFactoryFinalizerExtension {
|
||||
override fun finalizeClassFactory(factory: ClassFileFactory) {
|
||||
// We need to wait until the end to produce any output in order to strip classes
|
||||
// from the InnerClasses attributes.
|
||||
val outputFiles = AbiOutputFiles(abiClassInfos, factory)
|
||||
if (outputPath.extension == "jar") {
|
||||
// We don't include the runtime or main class in interface jars and always reset time stamps.
|
||||
CompileEnvironmentUtil.writeToJar(outputPath, false, true, true, null, outputFiles, MessageCollector.NONE)
|
||||
} else {
|
||||
outputFiles.writeAllTo(outputPath)
|
||||
}
|
||||
}
|
||||
|
||||
private class AbiOutputFiles(val abiClassInfos: Map<String, AbiClassInfo>, val outputFiles: OutputFileCollection) : OutputFileCollection {
|
||||
override fun get(relativePath: String): OutputFile? {
|
||||
error("AbiOutputFiles does not implement `get`.")
|
||||
}
|
||||
|
||||
override fun asList(): List<OutputFile> {
|
||||
val metadata = outputFiles.asList().filter {
|
||||
!it.relativePath.endsWith(".class")
|
||||
}.sortedBy { it.relativePath }
|
||||
|
||||
val classFiles = abiClassInfos.keys.sorted().mapNotNull { internalName ->
|
||||
val outputFile = outputFiles.get("$internalName.class")
|
||||
val abiInfo = abiClassInfos.getValue(internalName)
|
||||
when {
|
||||
// Note that outputFile may be null, e.g., for empty $DefaultImpls classes in the JVM backend.
|
||||
outputFile == null ->
|
||||
null
|
||||
|
||||
abiInfo is AbiClassInfo.Public ->
|
||||
// Copy verbatim
|
||||
outputFile
|
||||
|
||||
else -> /* abiInfo is AbiClassInfo.Stripped */ {
|
||||
val methodInfo = (abiInfo as AbiClassInfo.Stripped).methodInfo
|
||||
val writer = ClassWriter(0)
|
||||
ClassReader(outputFile.asByteArray()).accept(object : ClassVisitor(Opcodes.API_VERSION, writer) {
|
||||
// We remember all non-inline declarations in the stripped class so that we can
|
||||
// order them deterministically after all inline methods.
|
||||
private val fieldNodes = mutableListOf<FieldNode>()
|
||||
private val methodNodes = mutableListOf<StrippedMethodNode>()
|
||||
|
||||
// Strip private fields.
|
||||
override fun visitField(access: Int, name: String?, descriptor: String?, signature: String?, value: Any?): FieldVisitor? {
|
||||
if (access and Opcodes.ACC_PRIVATE != 0)
|
||||
return null
|
||||
return FieldNode(Opcodes.API_VERSION, access, name, descriptor, signature, value).also {
|
||||
fieldNodes += it
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitMethod(access: Int, name: String, descriptor: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||
val info = methodInfo[Method(name, descriptor)]
|
||||
?: return null
|
||||
|
||||
if (info == AbiMethodInfo.KEEP)
|
||||
return super.visitMethod(access, name, descriptor, signature, exceptions)
|
||||
|
||||
return StrippedMethodNode(access, name, descriptor, signature, exceptions).also {
|
||||
methodNodes += it
|
||||
}
|
||||
}
|
||||
|
||||
// Strip source debug extensions if there are no inline functions.
|
||||
override fun visitSource(source: String?, debug: String?) {
|
||||
// TODO Normalize and strip unused line numbers from SourceDebugExtensions
|
||||
if (methodInfo.values.any { it == AbiMethodInfo.KEEP })
|
||||
super.visitSource(source, debug)
|
||||
else
|
||||
super.visitSource(source, null)
|
||||
}
|
||||
|
||||
// Remove inner classes which are not present in the abi jar.
|
||||
override fun visitInnerClass(name: String?, outerName: String?, innerName: String?, access: Int) {
|
||||
if (name in abiClassInfos.keys) {
|
||||
super.visitInnerClass(name, outerName, innerName, access)
|
||||
}
|
||||
}
|
||||
|
||||
// Strip private declarations from the Kotlin Metadata annotation.
|
||||
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {
|
||||
val delegate = super.visitAnnotation(descriptor, visible)
|
||||
if (descriptor != JvmAnnotationNames.METADATA_DESC)
|
||||
return delegate
|
||||
return abiMetadataProcessor(internalName, abiClassInfos.keys, delegate)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
fieldNodes.sortBy { "${it.name}${it.desc}" }
|
||||
methodNodes.sortBy { "${it.name}${it.desc}" }
|
||||
for (field in fieldNodes) {
|
||||
field.accept(writer)
|
||||
}
|
||||
for (method in methodNodes) {
|
||||
method.accept(writer)
|
||||
}
|
||||
super.visitEnd()
|
||||
}
|
||||
}, 0)
|
||||
SimpleOutputBinaryFile(outputFile.sourceFiles, outputFile.relativePath, writer.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metadata + classFiles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class StrippedMethodNode(
|
||||
val access: Int,
|
||||
val name: String,
|
||||
val desc: String,
|
||||
val signature: String?,
|
||||
val exceptions: Array<out String>?,
|
||||
) : MethodVisitor(Opcodes.API_VERSION) {
|
||||
private class MethodAnnotation(
|
||||
val visible: Boolean,
|
||||
val node: AnnotationNode,
|
||||
)
|
||||
|
||||
private class MethodTypeAnnotation(
|
||||
val typeRef: Int,
|
||||
val typePath: TypePath?,
|
||||
val visible: Boolean,
|
||||
val node: AnnotationNode,
|
||||
)
|
||||
|
||||
private class MethodParameterAnnotation(
|
||||
val parameter: Int,
|
||||
val visible: Boolean,
|
||||
val node: AnnotationNode,
|
||||
)
|
||||
|
||||
private val parameters = mutableListOf<ParameterNode>()
|
||||
private val annotations = mutableListOf<MethodAnnotation>()
|
||||
private val typeAnnotations = mutableListOf<MethodTypeAnnotation>()
|
||||
private var visibleAnnotableParameterCount = 0
|
||||
private var invisibleAnnotableParameterCount = 0
|
||||
private val parameterAnnotations = mutableListOf<MethodParameterAnnotation>()
|
||||
private val attributes = mutableListOf<Attribute>()
|
||||
|
||||
override fun visitParameter(name: String?, access: Int) {
|
||||
parameters.add(ParameterNode(name, access))
|
||||
}
|
||||
|
||||
override fun visitAnnotation(descriptor: String, visible: Boolean): AnnotationVisitor =
|
||||
AnnotationNode(Opcodes.API_VERSION, descriptor).also {
|
||||
annotations.add(MethodAnnotation(visible, it))
|
||||
}
|
||||
|
||||
override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, descriptor: String, visible: Boolean): AnnotationVisitor =
|
||||
AnnotationNode(Opcodes.API_VERSION, descriptor).also {
|
||||
typeAnnotations.add(MethodTypeAnnotation(typeRef, typePath, visible, it))
|
||||
}
|
||||
|
||||
override fun visitAttribute(attribute: Attribute) {
|
||||
attributes.add(attribute)
|
||||
}
|
||||
|
||||
override fun visitAnnotableParameterCount(parameterCount: Int, visible: Boolean) {
|
||||
if (visible) {
|
||||
visibleAnnotableParameterCount = parameterCount
|
||||
} else {
|
||||
invisibleAnnotableParameterCount = parameterCount
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitParameterAnnotation(parameter: Int, descriptor: String, visible: Boolean): AnnotationVisitor =
|
||||
AnnotationNode(Opcodes.API_VERSION, descriptor).also {
|
||||
parameterAnnotations.add(MethodParameterAnnotation(parameter, visible, it))
|
||||
}
|
||||
|
||||
fun accept(classVisitor: ClassVisitor) {
|
||||
val visitor = classVisitor.visitMethod(access, name, desc, signature, exceptions)
|
||||
|
||||
for (parameter in parameters) {
|
||||
visitor.visitParameter(parameter.name, parameter.access)
|
||||
}
|
||||
|
||||
for (annotation in annotations) {
|
||||
visitor.visitAnnotation(annotation.node.desc, annotation.visible)?.let {
|
||||
annotation.node.accept(it)
|
||||
}
|
||||
}
|
||||
|
||||
for (typeAnnotation in typeAnnotations) {
|
||||
visitor.visitTypeAnnotation(
|
||||
typeAnnotation.typeRef,
|
||||
typeAnnotation.typePath,
|
||||
typeAnnotation.node.desc,
|
||||
typeAnnotation.visible,
|
||||
)?.let {
|
||||
typeAnnotation.node.accept(it)
|
||||
}
|
||||
}
|
||||
|
||||
visitor.visitAnnotableParameterCount(visibleAnnotableParameterCount, true)
|
||||
visitor.visitAnnotableParameterCount(invisibleAnnotableParameterCount, false)
|
||||
for (parameterAnnotation in parameterAnnotations) {
|
||||
visitor.visitParameterAnnotation(
|
||||
parameterAnnotation.parameter,
|
||||
parameterAnnotation.node.desc,
|
||||
parameterAnnotation.visible
|
||||
)?.let {
|
||||
parameterAnnotation.node.accept(it)
|
||||
}
|
||||
}
|
||||
|
||||
for (attribute in attributes) {
|
||||
visitor.visitAttribute(attribute)
|
||||
}
|
||||
|
||||
if (access and (Opcodes.ACC_NATIVE or Opcodes.ACC_ABSTRACT) == 0) {
|
||||
visitor.visitCode()
|
||||
visitor.visitInsn(Opcodes.ACONST_NULL)
|
||||
visitor.visitInsn(Opcodes.ATHROW)
|
||||
visitor.visitMaxs(0, parameters.size)
|
||||
}
|
||||
visitor.visitEnd()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import org.jetbrains.kotlin.incremental.testingUtils.assertEqualDirectories
|
||||
import java.io.File
|
||||
import kotlin.test.assertFails
|
||||
|
||||
abstract class AbstractIrCompareJvmAbiTest : AbstractCompareJvmAbiTest() {
|
||||
override val useIrBackend = true
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
|
||||
abstract class AbstractIrCompileAgainstJvmAbiTest : AbstractCompileAgainstJvmAbiTest() {
|
||||
override val useIrBackend = true
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
import com.intellij.openapi.util.io.systemIndependentPath
|
||||
import org.jetbrains.kotlin.codegen.BytecodeListingTextCollectingVisitor
|
||||
import org.jetbrains.kotlin.incremental.isClassFile
|
||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractIrJvmAbiContentTest : AbstractJvmAbiContentTest() {
|
||||
override val useIrBackend = true
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
abstract class AbstractLegacyCompareJvmAbiTest : AbstractCompareJvmAbiTest() {
|
||||
override val useLegacyAbiGen: Boolean
|
||||
get() = true
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
abstract class AbstractLegacyCompileAgainstJvmAbiTest : AbstractCompileAgainstJvmAbiTest() {
|
||||
override val useLegacyAbiGen: Boolean
|
||||
get() = true
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi
|
||||
|
||||
abstract class AbstractLegacyJvmAbiContentTest : AbstractJvmAbiContentTest() {
|
||||
override val useLegacyAbiGen: Boolean
|
||||
get() = true
|
||||
}
|
||||
@@ -64,8 +64,12 @@ abstract class BaseJvmAbiTest : TestCase() {
|
||||
freeArgs = listOf(compilation.srcDir.canonicalPath)
|
||||
classpath = (abiDependencies + kotlinJvmStdlib).joinToString(File.pathSeparator) { it.canonicalPath }
|
||||
pluginClasspaths = arrayOf(abiPluginJar.canonicalPath)
|
||||
pluginOptions = arrayOf(abiOption("outputDir", compilation.abiDir.canonicalPath))
|
||||
pluginOptions = listOfNotNull(
|
||||
abiOption(JvmAbiCommandLineProcessor.OUTPUT_PATH_OPTION.optionName, compilation.abiDir.canonicalPath),
|
||||
if (useLegacyAbiGen) abiOption("useLegacyAbiGen", "true") else null
|
||||
).toTypedArray()
|
||||
destination = compilation.destinationDir.canonicalPath
|
||||
useOldBackend = !useIrBackend
|
||||
}
|
||||
val exitCode = compiler.exec(messageCollector, Services.EMPTY, args)
|
||||
if (exitCode != ExitCode.OK || messageCollector.errors.isNotEmpty()) {
|
||||
@@ -74,6 +78,12 @@ abstract class BaseJvmAbiTest : TestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
protected open val useIrBackend: Boolean
|
||||
get() = false
|
||||
|
||||
protected open val useLegacyAbiGen: Boolean
|
||||
get() = false
|
||||
|
||||
protected val kotlinJvmStdlib = File("dist/kotlinc/lib/kotlin-stdlib.jar").also {
|
||||
check(it.exists()) { "Stdlib file '$it' does not exist" }
|
||||
}
|
||||
|
||||
+3
-2
@@ -9,6 +9,7 @@ import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -22,11 +23,11 @@ import java.util.regex.Pattern;
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class CompareJvmAbiTestGenerated extends AbstractCompareJvmAbiTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompare() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compare"), Pattern.compile("^([^\\.]+)$"), null, false);
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compare"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM, false);
|
||||
}
|
||||
|
||||
@TestMetadata("classFlags")
|
||||
|
||||
Generated
+3
-2
@@ -9,6 +9,7 @@ import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -22,11 +23,11 @@ import java.util.regex.Pattern;
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class CompileAgainstJvmAbiTestGenerated extends AbstractCompileAgainstJvmAbiTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompile() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compile"), Pattern.compile("^([^\\.]+)$"), null, false);
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compile"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM, false);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObject")
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/jvm-abi-gen/testData/compare")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class IrCompareJvmAbiTestGenerated extends AbstractIrCompareJvmAbiTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompare() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compare"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM_IR, false);
|
||||
}
|
||||
|
||||
@TestMetadata("classFlags")
|
||||
public void testClassFlags() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/classFlags/");
|
||||
}
|
||||
|
||||
@TestMetadata("classPrivateMemebers")
|
||||
public void testClassPrivateMemebers() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/classPrivateMemebers/");
|
||||
}
|
||||
|
||||
@TestMetadata("clinit")
|
||||
public void testClinit() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/clinit/");
|
||||
}
|
||||
|
||||
@TestMetadata("constant")
|
||||
public void testConstant() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/constant/");
|
||||
}
|
||||
|
||||
@TestMetadata("functionBody")
|
||||
public void testFunctionBody() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/functionBody/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionBody")
|
||||
public void testInlineFunctionBody() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/inlineFunctionBody/");
|
||||
}
|
||||
|
||||
@TestMetadata("parameterName")
|
||||
public void testParameterName() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/parameterName/");
|
||||
}
|
||||
|
||||
@TestMetadata("privateTypealias")
|
||||
public void testPrivateTypealias() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/privateTypealias/");
|
||||
}
|
||||
|
||||
@TestMetadata("returnType")
|
||||
public void testReturnType() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/returnType/");
|
||||
}
|
||||
|
||||
@TestMetadata("superClass")
|
||||
public void testSuperClass() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/superClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelPrivateMembers")
|
||||
public void testTopLevelPrivateMembers() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/topLevelPrivateMembers/");
|
||||
}
|
||||
}
|
||||
Generated
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/jvm-abi-gen/testData/compile")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class IrCompileAgainstJvmAbiTestGenerated extends AbstractIrCompileAgainstJvmAbiTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompile() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compile"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM_IR, false);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObject")
|
||||
public void testAnonymousObject() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/anonymousObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("classes")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/classes/");
|
||||
}
|
||||
|
||||
@TestMetadata("clinit")
|
||||
public void testClinit() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/clinit/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineAnonymousObject")
|
||||
public void testInlineAnonymousObject() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineAnonymousObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineCapture")
|
||||
public void testInlineCapture() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineReifiedFunction")
|
||||
public void testInlineReifiedFunction() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("privateOnlyConstructors")
|
||||
public void testPrivateOnlyConstructors() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevel")
|
||||
public void testTopLevel() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/topLevel/");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/jvm-abi-gen/testData/content")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class IrJvmAbiContentTestGenerated extends AbstractIrJvmAbiContentTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInContent() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/content"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM_IR, false);
|
||||
}
|
||||
|
||||
@TestMetadata("class")
|
||||
public void testClass() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/content/class/");
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -9,6 +9,7 @@ import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -22,11 +23,11 @@ import java.util.regex.Pattern;
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class JvmAbiContentTestGenerated extends AbstractJvmAbiContentTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInContent() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/content"), Pattern.compile("^([^\\.]+)$"), null, false);
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/content"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM, false);
|
||||
}
|
||||
|
||||
@TestMetadata("class")
|
||||
|
||||
Generated
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/jvm-abi-gen/testData/compare")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class LegacyCompareJvmAbiTestGenerated extends AbstractLegacyCompareJvmAbiTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM, testDataFilePath, "// IGNORE_BACKEND_LEGACY: ");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompare() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compare"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM, false);
|
||||
}
|
||||
|
||||
@TestMetadata("classFlags")
|
||||
public void testClassFlags() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/classFlags/");
|
||||
}
|
||||
|
||||
@TestMetadata("classPrivateMemebers")
|
||||
public void testClassPrivateMemebers() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/classPrivateMemebers/");
|
||||
}
|
||||
|
||||
@TestMetadata("clinit")
|
||||
public void testClinit() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/clinit/");
|
||||
}
|
||||
|
||||
@TestMetadata("constant")
|
||||
public void testConstant() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/constant/");
|
||||
}
|
||||
|
||||
@TestMetadata("functionBody")
|
||||
public void testFunctionBody() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/functionBody/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineFunctionBody")
|
||||
public void testInlineFunctionBody() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/inlineFunctionBody/");
|
||||
}
|
||||
|
||||
@TestMetadata("parameterName")
|
||||
public void testParameterName() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/parameterName/");
|
||||
}
|
||||
|
||||
@TestMetadata("privateTypealias")
|
||||
public void testPrivateTypealias() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/privateTypealias/");
|
||||
}
|
||||
|
||||
@TestMetadata("returnType")
|
||||
public void testReturnType() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/returnType/");
|
||||
}
|
||||
|
||||
@TestMetadata("superClass")
|
||||
public void testSuperClass() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/superClass/");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelPrivateMembers")
|
||||
public void testTopLevelPrivateMembers() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compare/topLevelPrivateMembers/");
|
||||
}
|
||||
}
|
||||
Generated
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/jvm-abi-gen/testData/compile")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class LegacyCompileAgainstJvmAbiTestGenerated extends AbstractLegacyCompileAgainstJvmAbiTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM, testDataFilePath, "// IGNORE_BACKEND_LEGACY: ");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompile() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/compile"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM, false);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObject")
|
||||
public void testAnonymousObject() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/anonymousObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("classes")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/classes/");
|
||||
}
|
||||
|
||||
@TestMetadata("clinit")
|
||||
public void testClinit() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/clinit/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineAnonymousObject")
|
||||
public void testInlineAnonymousObject() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineAnonymousObject/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineCapture")
|
||||
public void testInlineCapture() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineCapture/");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineReifiedFunction")
|
||||
public void testInlineReifiedFunction() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/inlineReifiedFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("privateOnlyConstructors")
|
||||
public void testPrivateOnlyConstructors() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/privateOnlyConstructors/");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevel")
|
||||
public void testTopLevel() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/compile/topLevel/");
|
||||
}
|
||||
}
|
||||
Generated
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.abi;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("plugins/jvm-abi-gen/testData/content")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class LegacyJvmAbiContentTestGenerated extends AbstractLegacyJvmAbiContentTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM, testDataFilePath, "// IGNORE_BACKEND_LEGACY: ");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInContent() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/jvm-abi-gen/testData/content"), Pattern.compile("^([^\\.]+)$"), null, TargetBackend.JVM, false);
|
||||
}
|
||||
|
||||
@TestMetadata("class")
|
||||
public void testClass() throws Exception {
|
||||
runTest("plugins/jvm-abi-gen/testData/content/class/");
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ open class A : I {
|
||||
fun aMethod(): Int = 30
|
||||
inline fun aInlineMethod(): Int = 40
|
||||
|
||||
private class AB {}
|
||||
|
||||
companion object {
|
||||
const val aConst: Int = 50
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user