Refactoring: Extract light analysis tests from box tests
This commit is contained in:
@@ -55,20 +55,12 @@ public class ClassBuilderFactories {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
};
|
||||
|
||||
public static ClassBuilderFactory TEST_KAPT3 = new TestClassBuilderFactory(false) {
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassBuilderMode getClassBuilderMode() {
|
||||
return ClassBuilderMode.KAPT3;
|
||||
}
|
||||
};
|
||||
|
||||
public static ClassBuilderFactory TEST = new TestClassBuilderFactory(false);
|
||||
|
||||
public static ClassBuilderFactory TEST_WITH_SOURCE_RETENTION_ANNOTATIONS = new TestClassBuilderFactory(true);
|
||||
|
||||
private static class TestClassBuilderFactory implements ClassBuilderFactory {
|
||||
public static class TestClassBuilderFactory implements ClassBuilderFactory {
|
||||
private final boolean generateSourceRetentionAnnotations;
|
||||
|
||||
public TestClassBuilderFactory(boolean generateSourceRetentionAnnotations) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen;
|
||||
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
public class ClassBuilderMode {
|
||||
public final boolean generateBodies;
|
||||
public final boolean generateMetadata;
|
||||
@@ -73,4 +75,11 @@ public class ClassBuilderMode {
|
||||
/* metadata = */ true,
|
||||
/* sourceRetention = */ true,
|
||||
/* generateMultiFileFacadePartClasses = */ true);
|
||||
|
||||
@TestOnly
|
||||
public final static ClassBuilderMode LIGHT_ANALYSIS_FOR_TESTS = new ClassBuilderMode(
|
||||
/* bodies = */ false,
|
||||
/* metadata = */ true,
|
||||
/* sourceRetention = */ false,
|
||||
/* generateMultiFileFacadePartClasses = */ true);
|
||||
}
|
||||
|
||||
@@ -920,17 +920,23 @@ public class FunctionCodegen {
|
||||
// enum constructors have two additional synthetic parameters which somewhat complicate this task
|
||||
AnnotationCodegen.forMethod(mv, memberCodegen, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType());
|
||||
|
||||
if (state.getClassBuilderMode().generateBodies) {
|
||||
if (this.owner instanceof MultifileClassFacadeContext) {
|
||||
mv.visitCode();
|
||||
generateFacadeDelegateMethodBody(mv, defaultMethod, (MultifileClassFacadeContext) this.owner);
|
||||
if (!state.getClassBuilderMode().generateBodies) {
|
||||
if (this.owner instanceof MultifileClassFacadeContext)
|
||||
endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
else {
|
||||
mv.visitCode();
|
||||
generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod);
|
||||
else
|
||||
endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.owner instanceof MultifileClassFacadeContext) {
|
||||
mv.visitCode();
|
||||
generateFacadeDelegateMethodBody(mv, defaultMethod, (MultifileClassFacadeContext) this.owner);
|
||||
endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
else {
|
||||
mv.visitCode();
|
||||
generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod);
|
||||
endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
int access = 0;
|
||||
|
||||
if (!state.getClassBuilderMode().generateBodies && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
// !ClassBuilderMode.generateBodies means we are generating light classes & looking at a nested or inner class
|
||||
// Light class generation is implemented so that Cls-classes only read bare code of classes,
|
||||
// without knowing whether these classes are inner or not (see ClassStubBuilder.EMPTY_STRATEGY)
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS, NATIVE
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
|
||||
// WITH_RUNTIME
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: Baz.java
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
Vendored
+1
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// KOTLIN_CONFIGURATION_FLAGS: +JVM.INHERIT_MULTIFILE_PARTS
|
||||
// FILE: box.kt
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
|
||||
// FILE: SingletonCollection.kt
|
||||
package test
|
||||
|
||||
+1
-47
@@ -19,20 +19,15 @@ package org.jetbrains.kotlin.codegen;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import kotlin.Unit;
|
||||
import kotlin.io.FilesKt;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction;
|
||||
import org.jetbrains.kotlin.psi.KtProperty;
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension;
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension;
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind;
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
|
||||
import org.jetbrains.kotlin.test.TestJdkKind;
|
||||
@@ -44,9 +39,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {
|
||||
// Set to 'true' to speed up black box tests locally
|
||||
private static final boolean SKIP_LIGHT_ANALYSIS_MODE_TESTS = false;
|
||||
|
||||
private boolean addRuntime = false;
|
||||
private boolean addReflect = false;
|
||||
|
||||
@@ -71,45 +63,7 @@ public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {
|
||||
addRuntime ? ConfigurationKind.NO_KOTLIN_REFLECT :
|
||||
ConfigurationKind.JDK_ONLY;
|
||||
|
||||
try {
|
||||
compileAndRun(files, javaFilesDir, jdkKind, javacOptions);
|
||||
}
|
||||
catch (Throwable boxError) {
|
||||
// Even if black box fails, run light analysis mode test to generate the .txt file
|
||||
try {
|
||||
doLightAnalysisModeTest(wholeFile, files, javaFilesDir);
|
||||
}
|
||||
catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
throw ExceptionUtilsKt.rethrow(boxError);
|
||||
}
|
||||
|
||||
doLightAnalysisModeTest(wholeFile, files, javaFilesDir);
|
||||
}
|
||||
|
||||
private void doLightAnalysisModeTest(@NotNull File wholeFile, @NotNull List<TestFile> files, @Nullable File javaFilesDir) {
|
||||
if (SKIP_LIGHT_ANALYSIS_MODE_TESTS) return;
|
||||
|
||||
File boxTestsDir = new File("compiler/testData/codegen/box");
|
||||
String relativePath = FilesKt.toRelativeString(wholeFile, boxTestsDir);
|
||||
// Do nothing if this test is not under codegen/box
|
||||
if (relativePath.startsWith("..")) return;
|
||||
|
||||
String outDir = new File("compiler/testData/codegen/light-analysis", relativePath).getParent();
|
||||
File txtFile = new File(outDir, FilesKt.getNameWithoutExtension(wholeFile) + ".txt");
|
||||
AbstractBytecodeListingTest.doTest(
|
||||
getTestRootDisposable(), files, javaFilesDir, txtFile, ClassBuilderFactories.TEST_KAPT3,
|
||||
new Function1<KotlinCoreEnvironment, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(KotlinCoreEnvironment environment) {
|
||||
AnalysisHandlerExtension.Companion.registerExtension(
|
||||
environment.getProject(), new PartialAnalysisHandlerExtension()
|
||||
);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
}
|
||||
);
|
||||
compileAndRun(files, javaFilesDir, jdkKind, javacOptions);
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFile
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
@@ -48,6 +49,18 @@ abstract class AbstractBytecodeListingTest : CodegenTestCase() {
|
||||
classBuilderFactory: ClassBuilderFactory,
|
||||
setupEnvironment: (KotlinCoreEnvironment) -> Unit = {}
|
||||
) {
|
||||
val classFileFactory = compileClasses(disposable, files, javaFilesDir, classBuilderFactory, setupEnvironment)
|
||||
val actualTxt = BytecodeListingTextCollectingVisitor.getText(classFileFactory)
|
||||
KotlinTestUtils.assertEqualsToFile(txtFile, actualTxt)
|
||||
}
|
||||
|
||||
fun compileClasses(
|
||||
disposable: Disposable,
|
||||
files: List<TestFile>,
|
||||
javaFilesDir: File?,
|
||||
classBuilderFactory: ClassBuilderFactory,
|
||||
setupEnvironment: (KotlinCoreEnvironment) -> Unit = {}
|
||||
): ClassFileFactory {
|
||||
val addRuntime = files.any { InTextDirectivesUtils.isDirectiveDefined(it.content, "WITH_RUNTIME") }
|
||||
val addReflect = files.any { InTextDirectivesUtils.isDirectiveDefined(it.content, "WITH_REFLECT") }
|
||||
|
||||
@@ -63,22 +76,48 @@ abstract class AbstractBytecodeListingTest : CodegenTestCase() {
|
||||
val environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
|
||||
setupEnvironment(environment)
|
||||
|
||||
val generatedFiles = CodegenTestUtil.generateFiles(environment, loadMultiFiles(files, environment.project), classBuilderFactory)
|
||||
.getClassFiles()
|
||||
.sortedBy { it.relativePath }
|
||||
.map {
|
||||
val cr = ClassReader(it.asByteArray())
|
||||
val visitor = BytecodeListingTextCollectingVisitor()
|
||||
cr.accept(visitor, ClassReader.SKIP_CODE)
|
||||
KotlinTestUtils.replaceHash(visitor.text, "HASH")
|
||||
}.joinToString("\n\n", postfix = "\n")
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(txtFile, generatedFiles)
|
||||
return CodegenTestUtil.generateFiles(environment, loadMultiFiles(files, environment.project), classBuilderFactory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class BytecodeListingTextCollectingVisitor : ClassVisitor(ASM5) {
|
||||
class BytecodeListingTextCollectingVisitor(val filter: Filter) : ClassVisitor(ASM5) {
|
||||
companion object {
|
||||
fun getText(factory: ClassFileFactory, filter: Filter = Filter.EMPTY, replaceHash: Boolean = true) = factory
|
||||
.getClassFiles()
|
||||
.sortedBy { it.relativePath }
|
||||
.mapNotNull {
|
||||
val cr = ClassReader(it.asByteArray())
|
||||
val visitor = BytecodeListingTextCollectingVisitor(filter)
|
||||
cr.accept(visitor, ClassReader.SKIP_CODE)
|
||||
|
||||
if (!filter.shouldWriteClass(cr.access, cr.className)) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
if (replaceHash) {
|
||||
KotlinTestUtils.replaceHash(visitor.text, "HASH")
|
||||
}
|
||||
else {
|
||||
visitor.text
|
||||
}
|
||||
}.joinToString("\n\n", postfix = "\n")
|
||||
}
|
||||
|
||||
interface Filter {
|
||||
fun shouldWriteClass(access: Int, name: String): Boolean
|
||||
fun shouldWriteMethod(access: Int, name: String, desc: String): Boolean
|
||||
fun shouldWriteField(access: Int, name: String, desc: String): Boolean
|
||||
fun shouldWriteInnerClass(name: String): Boolean
|
||||
|
||||
object EMPTY : Filter {
|
||||
override fun shouldWriteClass(access: Int, name: String) = true
|
||||
override fun shouldWriteMethod(access: Int, name: String, desc: String) = true
|
||||
override fun shouldWriteField(access: Int, name: String, desc: String) = true
|
||||
override fun shouldWriteInnerClass(name: String) = true
|
||||
}
|
||||
}
|
||||
|
||||
private class Declaration(val text: String, val annotations: MutableList<String> = arrayListOf())
|
||||
|
||||
private val declarationsInsideClass = arrayListOf<Declaration>()
|
||||
@@ -141,6 +180,10 @@ private class BytecodeListingTextCollectingVisitor : ClassVisitor(ASM5) {
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor? {
|
||||
if (!filter.shouldWriteMethod(access, name, desc)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val returnType = Type.getReturnType(desc).className
|
||||
val parameterTypes = Type.getArgumentTypes(desc).map { it.className }
|
||||
val methodAnnotations = arrayListOf<String>()
|
||||
@@ -173,6 +216,10 @@ private class BytecodeListingTextCollectingVisitor : ClassVisitor(ASM5) {
|
||||
}
|
||||
|
||||
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
||||
if (!filter.shouldWriteField(access, name, desc)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val type = Type.getType(desc).className
|
||||
val fieldDeclaration = Declaration("field $name: $type")
|
||||
declarationsInsideClass.add(fieldDeclaration)
|
||||
@@ -206,6 +253,9 @@ private class BytecodeListingTextCollectingVisitor : ClassVisitor(ASM5) {
|
||||
}
|
||||
|
||||
override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) {
|
||||
if (!filter.shouldWriteInnerClass(name)) {
|
||||
return
|
||||
}
|
||||
declarationsInsideClass.add(Declaration("inner class $name"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping.*
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PartialAnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
|
||||
import java.io.File
|
||||
import java.util.ArrayList
|
||||
|
||||
abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
|
||||
private companion object {
|
||||
var TEST_LIGHT_ANALYSIS: ClassBuilderFactory = object : ClassBuilderFactories.TestClassBuilderFactory(false) {
|
||||
override fun getClassBuilderMode() = ClassBuilderMode.LIGHT_ANALYSIS_FOR_TESTS
|
||||
}
|
||||
}
|
||||
|
||||
override fun doMultiFileTest(wholeFile: File, files: List<CodegenTestCase.TestFile>, javaFilesDir: File?) {
|
||||
val jdkKind = CodegenTestCase.getJdkKind(files)
|
||||
|
||||
val javacOptions = ArrayList<String>(0)
|
||||
var addRuntime = false
|
||||
var addReflect = false
|
||||
|
||||
for (file in files) {
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_RUNTIME")) {
|
||||
addRuntime = true
|
||||
}
|
||||
if (InTextDirectivesUtils.isDirectiveDefined(file.content, "WITH_REFLECT")) {
|
||||
addReflect = true
|
||||
}
|
||||
|
||||
if (file.content.contains("// IGNORE_LIGHT_ANALYSIS")) {
|
||||
return
|
||||
}
|
||||
|
||||
javacOptions.addAll(InTextDirectivesUtils.findListWithPrefixes(file.content, "// JAVAC_OPTIONS:"))
|
||||
}
|
||||
|
||||
configurationKind = if (addReflect)
|
||||
ConfigurationKind.ALL
|
||||
else if (addRuntime)
|
||||
ConfigurationKind.NO_KOTLIN_REFLECT
|
||||
else
|
||||
ConfigurationKind.JDK_ONLY
|
||||
|
||||
val fullTxt = compileWithFullAnalysis(files, javaFilesDir, jdkKind, javacOptions)
|
||||
.replace("final enum class", "enum class")
|
||||
|
||||
val liteTxt = compileWithLightAnalysis(wholeFile, files, javaFilesDir)
|
||||
.replace("@synthetic.kotlin.jvm.GeneratedByJvmOverloads ", "")
|
||||
|
||||
assertEquals(fullTxt, liteTxt)
|
||||
}
|
||||
|
||||
private fun compileWithLightAnalysis(wholeFile: File, files: List<CodegenTestCase.TestFile>, javaFilesDir: File?): String {
|
||||
val boxTestsDir = File("compiler/testData/codegen/box")
|
||||
val relativePath = wholeFile.toRelativeString(boxTestsDir)
|
||||
// Fail if this test is not under codegen/box
|
||||
assert(!relativePath.startsWith(".."))
|
||||
|
||||
val classFileFactory = AbstractBytecodeListingTest.compileClasses(
|
||||
testRootDisposable, files, javaFilesDir, TEST_LIGHT_ANALYSIS,
|
||||
setupEnvironment = { env -> AnalysisHandlerExtension.registerExtension(env.project, PartialAnalysisHandlerExtension()) }
|
||||
)
|
||||
|
||||
return BytecodeListingTextCollectingVisitor.getText(classFileFactory, ListAnalysisFilter(), replaceHash = false)
|
||||
}
|
||||
|
||||
protected fun compileWithFullAnalysis(
|
||||
files: List<CodegenTestCase.TestFile>,
|
||||
javaSourceDir: File?,
|
||||
jdkKind: TestJdkKind,
|
||||
javacOptions: List<String>
|
||||
): String {
|
||||
compile(files, javaSourceDir, configurationKind, jdkKind, javacOptions)
|
||||
classFileFactory.getClassFiles()
|
||||
|
||||
val classInternalNames = classFileFactory.generationState.bindingContext
|
||||
.getSliceContents(CodegenBinding.ASM_TYPE).map { it.value.internalName to it.key }.toMap()
|
||||
|
||||
return BytecodeListingTextCollectingVisitor.getText(classFileFactory, object : ListAnalysisFilter() {
|
||||
override fun shouldWriteClass(access: Int, name: String): Boolean {
|
||||
val classDescriptor = classInternalNames[name]
|
||||
if (classDescriptor != null && shouldFilterClass(classDescriptor)) {
|
||||
return false
|
||||
}
|
||||
return super.shouldWriteClass(access, name)
|
||||
}
|
||||
|
||||
override fun shouldWriteInnerClass(name: String): Boolean {
|
||||
val classDescriptor = classInternalNames[name]
|
||||
if (classDescriptor != null && shouldFilterClass(classDescriptor)) {
|
||||
return false
|
||||
}
|
||||
return super.shouldWriteInnerClass(name)
|
||||
}
|
||||
|
||||
private fun shouldFilterClass(descriptor: ClassDescriptor): Boolean {
|
||||
return descriptor.visibility == Visibilities.LOCAL || descriptor is SyntheticClassDescriptorForLambda
|
||||
}
|
||||
}, replaceHash = false)
|
||||
}
|
||||
|
||||
private open class ListAnalysisFilter : BytecodeListingTextCollectingVisitor.Filter {
|
||||
override fun shouldWriteClass(access: Int, name: String) = when {
|
||||
name.endsWith(MAPPINGS_CLASS_NAME_POSTFIX) && (access and ACC_SYNTHETIC != 0) && (access and ACC_FINAL != 0) -> false
|
||||
name.contains("\$\$inlined") && (access and ACC_FINAL != 0) -> false
|
||||
name.contains("\$sam\$") -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
override fun shouldWriteMethod(access: Int, name: String, desc: String) = when {
|
||||
name == "<clinit>" -> false
|
||||
AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.descriptor in desc -> false
|
||||
name.startsWith("access$") && (access and ACC_STATIC != 0) && (access and ACC_SYNTHETIC != 0) -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
override fun shouldWriteField(access: Int, name: String, desc: String) = when {
|
||||
name == "\$VALUES" && (access and ACC_PRIVATE != 0) && (access and ACC_FINAL != 0) && (access and ACC_SYNTHETIC != 0) -> false
|
||||
else -> true
|
||||
}
|
||||
|
||||
override fun shouldWriteInnerClass(name: String) = true
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -238,6 +238,10 @@ fun main(args: Array<String>) {
|
||||
model("codegen/box", targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractLightAnalysisModeTest> {
|
||||
model("codegen/box", targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
testClass<AbstractIrBlackBoxCodegenTest>("IrOnlyBoxCodegenTestGenerated") {
|
||||
model("ir/box", targetBackend = TargetBackend.JVM)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user