Reformat and cleanup most JVM codegen test classes

This commit is contained in:
Alexander Udalov
2019-03-29 14:56:35 +01:00
parent 23a214710b
commit 7fdb9c990e
43 changed files with 491 additions and 580 deletions
@@ -33,9 +33,9 @@ public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase {
@Override @Override
protected void doMultiFileTest( protected void doMultiFileTest(
@NotNull File wholeFile, @NotNull File wholeFile,
@NotNull List<TestFile> files, @NotNull List<TestFile> files,
@Nullable File javaFilesDir @Nullable File javaFilesDir
) throws Exception { ) throws Exception {
boolean isIgnored = IGNORE_EXPECTED_FAILURES && InTextDirectivesUtils.isIgnoredTarget(getBackend(), wholeFile); boolean isIgnored = IGNORE_EXPECTED_FAILURES && InTextDirectivesUtils.isIgnoredTarget(getBackend(), wholeFile);
@@ -24,8 +24,7 @@ abstract class AbstractBlackBoxInlineCodegenTest : AbstractBlackBoxCodegenTest()
try { try {
InlineTestUtil.checkNoCallsToInline(initializedClassLoader.allGeneratedFiles.filterClassFiles(), myFiles.psiFiles) InlineTestUtil.checkNoCallsToInline(initializedClassLoader.allGeneratedFiles.filterClassFiles(), myFiles.psiFiles)
SMAPTestUtil.checkSMAP(files, generateClassesInFile().getClassFiles(), false) SMAPTestUtil.checkSMAP(files, generateClassesInFile().getClassFiles(), false)
} } catch (e: Throwable) {
catch (e: Throwable) {
println(generateToText()) println(generateToText())
throw e throw e
} }
@@ -34,7 +34,7 @@ abstract class AbstractBytecodeListingTest : CodegenTestCase() {
} }
private fun isWithSignatures(wholeFile: File): Boolean = private fun isWithSignatures(wholeFile: File): Boolean =
WITH_SIGNATURES.containsMatchIn(wholeFile.readText()) WITH_SIGNATURES.containsMatchIn(wholeFile.readText())
companion object { companion object {
private val WITH_SIGNATURES = Regex.fromLiteral("// WITH_SIGNATURES") private val WITH_SIGNATURES = Regex.fromLiteral("// WITH_SIGNATURES")
@@ -132,13 +132,7 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter, val withSignature
} }
}.toString() }.toString()
override fun visitMethod( override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
if (!filter.shouldWriteMethod(access, name, desc)) { if (!filter.shouldWriteMethod(access, name, desc)) {
return null return null
} }
@@ -176,7 +170,7 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter, val withSignature
}.joinToString() }.joinToString()
val signatureIfRequired = if (withSignatures) "<$signature> " else "" val signatureIfRequired = if (withSignatures) "<$signature> " else ""
declarationsInsideClass.add( declarationsInsideClass.add(
Declaration("${signatureIfRequired}method $name($parameterWithAnnotations): $returnType", methodAnnotations) Declaration("${signatureIfRequired}method $name($parameterWithAnnotations): $returnType", methodAnnotations)
) )
super.visitEnd() super.visitEnd()
} }
@@ -218,14 +212,7 @@ class BytecodeListingTextCollectingVisitor(val filter: Filter, val withSignature
return super.visitAnnotation(desc, visible) return super.visitAnnotation(desc, visible)
} }
override fun visit( override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<out String>?) {
version: Int,
access: Int,
name: String,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
className = name className = name
classAccess = access classAccess = access
classSignature = signature classSignature = signature
@@ -5,12 +5,10 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.utils.rethrow
import org.junit.Assert import org.junit.Assert
import java.io.File import java.io.File
import java.util.* import java.util.*
@@ -18,24 +16,25 @@ import java.util.regex.Matcher
import java.util.regex.Pattern import java.util.regex.Pattern
abstract class AbstractBytecodeTextTest : CodegenTestCase() { abstract class AbstractBytecodeTextTest : CodegenTestCase() {
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
@Throws(Exception::class) createEnvironmentWithMockJdkAndIdeaAnnotations(
override fun doMultiFileTest(wholeFile: File, files: List<CodegenTestCase.TestFile>, javaFilesDir: File?) { ConfigurationKind.ALL,
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, files, TestJdkKind.MOCK_JDK, javaFilesDir) files,
TestJdkKind.MOCK_JDK,
*listOfNotNull(javaFilesDir).toTypedArray()
)
loadMultiFiles(files) loadMultiFiles(files)
if (isMultiFileTest(files) && !InTextDirectivesUtils.isDirectiveDefined(wholeFile.readText(), "TREAT_AS_ONE_FILE")) { if (isMultiFileTest(files) && !InTextDirectivesUtils.isDirectiveDefined(wholeFile.readText(), "TREAT_AS_ONE_FILE")) {
doTestMultiFile(files) doTestMultiFile(files)
} } else {
else {
val expected = readExpectedOccurrences(wholeFile.path) val expected = readExpectedOccurrences(wholeFile.path)
val actual = generateToText("helpers/") val actual = generateToText("helpers/")
checkGeneratedTextAgainstExpectedOccurrences(actual, expected) checkGeneratedTextAgainstExpectedOccurrences(actual, expected)
} }
} }
@Throws(Exception::class) private fun doTestMultiFile(files: List<TestFile>) {
private fun doTestMultiFile(files: List<CodegenTestCase.TestFile>) {
val expectedOccurrencesByOutputFile = LinkedHashMap<String, List<OccurrenceInfo>>() val expectedOccurrencesByOutputFile = LinkedHashMap<String, List<OccurrenceInfo>>()
for (file in files) { for (file in files) {
readExpectedOccurrencesForMultiFileTest(file, expectedOccurrencesByOutputFile) readExpectedOccurrencesForMultiFileTest(file, expectedOccurrencesByOutputFile)
@@ -50,10 +49,9 @@ abstract class AbstractBytecodeTextTest : CodegenTestCase() {
} }
} }
@Throws(Exception::class)
protected fun readExpectedOccurrences(filename: String): List<OccurrenceInfo> { protected fun readExpectedOccurrences(filename: String): List<OccurrenceInfo> {
val result = ArrayList<OccurrenceInfo>() val result = ArrayList<OccurrenceInfo>()
val lines = FileUtil.loadFile(File(filename), Charsets.UTF_8.name(), true).split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val lines = File(filename).readLines().dropLastWhile(String::isEmpty)
for (line in lines) { for (line in lines) {
val matcher = EXPECTED_OCCURRENCES_PATTERN.matcher(line) val matcher = EXPECTED_OCCURRENCES_PATTERN.matcher(line)
@@ -80,7 +78,7 @@ abstract class AbstractBytecodeTextTest : CodegenTestCase() {
private val AT_OUTPUT_FILE_PATTERN = Pattern.compile("^\\s*//\\s*@(.*):$") private val AT_OUTPUT_FILE_PATTERN = Pattern.compile("^\\s*//\\s*@(.*):$")
private val EXPECTED_OCCURRENCES_PATTERN = Pattern.compile("^\\s*//\\s*(\\d+)\\s*(.*)$") private val EXPECTED_OCCURRENCES_PATTERN = Pattern.compile("^\\s*//\\s*(\\d+)\\s*(.*)$")
private fun isMultiFileTest(files: List<CodegenTestCase.TestFile>): Boolean { private fun isMultiFileTest(files: List<TestFile>): Boolean {
var kotlinFiles = 0 var kotlinFiles = 0
for (file in files) { for (file in files) {
if (file.name.endsWith(".kt")) { if (file.name.endsWith(".kt")) {
@@ -90,8 +88,7 @@ abstract class AbstractBytecodeTextTest : CodegenTestCase() {
return kotlinFiles > 1 return kotlinFiles > 1
} }
fun checkGeneratedTextAgainstExpectedOccurrences(text: String, fun checkGeneratedTextAgainstExpectedOccurrences(text: String, expectedOccurrences: List<OccurrenceInfo>) {
expectedOccurrences: List<OccurrenceInfo>) {
val expected = StringBuilder() val expected = StringBuilder()
val actual = StringBuilder() val actual = StringBuilder()
@@ -102,10 +99,9 @@ abstract class AbstractBytecodeTextTest : CodegenTestCase() {
try { try {
Assert.assertEquals(text, expected.toString(), actual.toString()) Assert.assertEquals(text, expected.toString(), actual.toString())
} } catch (e: Throwable) {
catch (e: Throwable) {
println(text) println(text)
throw rethrow(e) throw e
} }
} }
@@ -121,27 +117,23 @@ abstract class AbstractBytecodeTextTest : CodegenTestCase() {
} }
} }
private fun readExpectedOccurrencesForMultiFileTest( private fun readExpectedOccurrencesForMultiFileTest(file: TestFile, occurrenceMap: MutableMap<String, List<OccurrenceInfo>>) {
file: CodegenTestCase.TestFile,
occurrenceMap: MutableMap<String, List<OccurrenceInfo>>) {
var currentOccurrenceInfos: MutableList<OccurrenceInfo>? = null var currentOccurrenceInfos: MutableList<OccurrenceInfo>? = null
for (line in file.content.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) { for (line in file.content.split("\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
val atOutputFileMatcher = AT_OUTPUT_FILE_PATTERN.matcher(line) val atOutputFileMatcher = AT_OUTPUT_FILE_PATTERN.matcher(line)
if (atOutputFileMatcher.matches()) { if (atOutputFileMatcher.matches()) {
val outputFileName = atOutputFileMatcher.group(1) val outputFileName = atOutputFileMatcher.group(1)
if (occurrenceMap.containsKey(outputFileName)) { if (occurrenceMap.containsKey(outputFileName)) {
throw AssertionError( throw AssertionError("${file.name}: Expected occurrences for output file $outputFileName were already provided")
file.name + ": Expected occurrences for output file " + outputFileName + " were already provided")
} }
currentOccurrenceInfos = ArrayList<OccurrenceInfo>() currentOccurrenceInfos = ArrayList()
occurrenceMap.put(outputFileName, currentOccurrenceInfos) occurrenceMap[outputFileName] = currentOccurrenceInfos
} }
val expectedOccurrencesMatcher = EXPECTED_OCCURRENCES_PATTERN.matcher(line) val expectedOccurrencesMatcher = EXPECTED_OCCURRENCES_PATTERN.matcher(line)
if (expectedOccurrencesMatcher.matches()) { if (expectedOccurrencesMatcher.matches()) {
if (currentOccurrenceInfos == null) { if (currentOccurrenceInfos == null) {
throw AssertionError( throw AssertionError("${file.name}: Should specify output file with '// @<OUTPUT_FILE_NAME>:' before expectations")
file.name + ": Should specify output file with '// @<OUTPUT_FILE_NAME>:' before expectations")
} }
val occurrenceInfo = parseOccurrenceInfo(expectedOccurrencesMatcher) val occurrenceInfo = parseOccurrenceInfo(expectedOccurrencesMatcher)
currentOccurrenceInfos.add(occurrenceInfo) currentOccurrenceInfos.add(occurrenceInfo)
@@ -26,8 +26,7 @@ abstract class AbstractCompileKotlinAgainstInlineKotlinTest : AbstractCompileKot
val sourceFiles = factory1.inputFiles + factory2.inputFiles val sourceFiles = factory1.inputFiles + factory2.inputFiles
InlineTestUtil.checkNoCallsToInline(allGeneratedFiles.filterClassFiles(), sourceFiles) InlineTestUtil.checkNoCallsToInline(allGeneratedFiles.filterClassFiles(), sourceFiles)
SMAPTestUtil.checkSMAP(files, allGeneratedFiles.filterClassFiles(), true) SMAPTestUtil.checkSMAP(files, allGeneratedFiles.filterClassFiles(), true)
} } catch (e: Throwable) {
catch (e: Throwable) {
println("FIRST:\n\n${factory1.createText()}\n\nSECOND:\n\n${factory2.createText()}") println("FIRST:\n\n${factory1.createText()}\n\nSECOND:\n\n${factory2.createText()}")
throw e throw e
} }
@@ -49,13 +49,13 @@ public abstract class AbstractCompileKotlinAgainstKotlinTest extends CodegenTest
} }
@Override @Override
protected void doMultiFileTest(@NotNull File wholeFile, @NotNull List<TestFile> files, @Nullable File javaFilesDir) throws Exception { protected void doMultiFileTest(@NotNull File wholeFile, @NotNull List<TestFile> files, @Nullable File javaFilesDir) {
assert javaFilesDir == null : ".java files are not supported yet in this test"; assert javaFilesDir == null : ".java files are not supported yet in this test";
doTwoFileTest(files); doTwoFileTest(files);
} }
@NotNull @NotNull
protected Pair<ClassFileFactory, ClassFileFactory> doTwoFileTest(@NotNull List<TestFile> files) throws Exception { protected Pair<ClassFileFactory, ClassFileFactory> doTwoFileTest(@NotNull List<TestFile> files) {
// Note that it may be beneficial to improve this test to handle many files, compiling them successively against all previous // Note that it may be beneficial to improve this test to handle many files, compiling them successively against all previous
assert files.size() == 2 || (files.size() == 3 && files.get(2).name.equals("CoroutineUtil.kt")) : "There should be exactly two files in this test"; assert files.size() == 2 || (files.size() == 3 && files.get(2).name.equals("CoroutineUtil.kt")) : "There should be exactly two files in this test";
TestFile fileA = files.get(0); TestFile fileA = files.get(0);
@@ -17,7 +17,7 @@ abstract class AbstractDumpDeclarationsTest : CodegenTestCase() {
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) { override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val expectedResult = KotlinTestUtils.replaceExtension(wholeFile, "json") val expectedResult = KotlinTestUtils.replaceExtension(wholeFile, "json")
dumpToFile = KotlinTestUtils.tmpDirForTest(this).resolve(name + ".json") dumpToFile = KotlinTestUtils.tmpDirForTest(this).resolve("$name.json")
compile(files, null) compile(files, null)
classFileFactory.generationState.destroy() classFileFactory.generationState.destroy()
KotlinTestUtils.assertEqualsToFile(expectedResult, dumpToFile.readText()) { KotlinTestUtils.assertEqualsToFile(expectedResult, dumpToFile.readText()) {
@@ -34,10 +34,10 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
} }
val fullTxt = compileWithFullAnalysis(files, javaFilesDir) val fullTxt = compileWithFullAnalysis(files, javaFilesDir)
.replace("final enum class", "enum class") .replace("final enum class", "enum class")
val liteTxt = compileWithLightAnalysis(wholeFile, files, javaFilesDir) val liteTxt = compileWithLightAnalysis(wholeFile, files, javaFilesDir)
.replace("@synthetic.kotlin.jvm.GeneratedByJvmOverloads ", "") .replace("@synthetic.kotlin.jvm.GeneratedByJvmOverloads ", "")
assertEquals(fullTxt, liteTxt) assertEquals(fullTxt, liteTxt)
} }
@@ -53,7 +53,7 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
assert(!relativePath.startsWith("..")) assert(!relativePath.startsWith(".."))
val configuration = createConfiguration( val configuration = createConfiguration(
configurationKind, getJdkKind(files), listOf(getAnnotationsJar()), javaFilesDir?.let(::listOf).orEmpty(), files configurationKind, getJdkKind(files), listOf(getAnnotationsJar()), javaFilesDir?.let(::listOf).orEmpty(), files
) )
val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
AnalysisHandlerExtension.registerExtension(environment.project, PartialAnalysisHandlerExtension()) AnalysisHandlerExtension.registerExtension(environment.project, PartialAnalysisHandlerExtension())
@@ -65,14 +65,14 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() {
} }
protected fun compileWithFullAnalysis( protected fun compileWithFullAnalysis(
files: List<TestFile>, files: List<TestFile>,
javaSourceDir: File? javaSourceDir: File?
): String { ): String {
compile(files, javaSourceDir) compile(files, javaSourceDir)
classFileFactory.getClassFiles() classFileFactory.getClassFiles()
val classInternalNames = classFileFactory.generationState.bindingContext val classInternalNames = classFileFactory.generationState.bindingContext
.getSliceContents(CodegenBinding.ASM_TYPE).map { it.value.internalName to it.key }.toMap() .getSliceContents(CodegenBinding.ASM_TYPE).map { it.value.internalName to it.key }.toMap()
return BytecodeListingTextCollectingVisitor.getText(classFileFactory, object : ListAnalysisFilter() { return BytecodeListingTextCollectingVisitor.getText(classFileFactory, object : ListAnalysisFilter() {
override fun shouldWriteClass(access: Int, name: String): Boolean { override fun shouldWriteClass(access: Int, name: String): Boolean {
@@ -29,7 +29,7 @@ import kotlin.collections.ArrayList
abstract class AbstractLineNumberTest : CodegenTestCase() { abstract class AbstractLineNumberTest : CodegenTestCase() {
override fun doMultiFileTest( override fun doMultiFileTest(
wholeFile: File, files: MutableList<CodegenTestCase.TestFile>, javaFilesDir: File? wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?
) { ) {
val isCustomTest = wholeFile.parentFile.name.equals("custom", ignoreCase = true) val isCustomTest = wholeFile.parentFile.name.equals("custom", ignoreCase = true)
if (!isCustomTest) { if (!isCustomTest) {
@@ -159,7 +159,7 @@ abstract class AbstractLineNumberTest : CodegenTestCase() {
private val TEST_LINE_NUMBER_PATTERN = Pattern.compile("^.*test.$LINE_NUMBER_FUN\\(\\).*$") private val TEST_LINE_NUMBER_PATTERN = Pattern.compile("^.*test.$LINE_NUMBER_FUN\\(\\).*$")
private fun createLineNumberDeclaration() = private fun createLineNumberDeclaration() =
CodegenTestCase.TestFile( TestFile(
"$LINE_NUMBER_FUN.kt", "$LINE_NUMBER_FUN.kt",
"package test;\n\npublic fun $LINE_NUMBER_FUN(): Int = 0\n" "package test;\n\npublic fun $LINE_NUMBER_FUN(): Int = 0\n"
) )
@@ -21,13 +21,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.config.CompilerConfiguration; import org.jetbrains.kotlin.config.CompilerConfiguration;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.test.TestJdkKind;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt; import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.io.File;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List;
import static org.jetbrains.kotlin.script.ScriptTestUtilKt.loadScriptingPlugin; import static org.jetbrains.kotlin.script.ScriptTestUtilKt.loadScriptingPlugin;
@@ -56,7 +56,6 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -82,7 +81,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
private static final String DEFAULT_TEST_FILE_NAME = "a_test"; private static final String DEFAULT_TEST_FILE_NAME = "a_test";
private static final String DEFAULT_JVM_TARGET_FOR_TEST = "kotlin.test.default.jvm.target"; private static final String DEFAULT_JVM_TARGET_FOR_TEST = "kotlin.test.default.jvm.target";
private static final String JAVA_COMPILATION_TARGET = "kotlin.test.java.compilation.target"; private static final String JAVA_COMPILATION_TARGET = "kotlin.test.java.compilation.target";
public static final String RUN_BOX_TEST_IN_SEPARATE_PROCESS_PORT = "kotlin.test.box.in.separate.process.port"; private static final String RUN_BOX_TEST_IN_SEPARATE_PROCESS_PORT = "kotlin.test.box.in.separate.process.port";
protected KotlinCoreEnvironment myEnvironment; protected KotlinCoreEnvironment myEnvironment;
protected CodegenTestFiles myFiles; protected CodegenTestFiles myFiles;
@@ -90,7 +89,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
protected GeneratedClassLoader initializedClassLoader; protected GeneratedClassLoader initializedClassLoader;
protected File javaClassesOutputDirectory = null; protected File javaClassesOutputDirectory = null;
protected List<File> additionalDependencies = null; protected List<File> additionalDependencies = null;
protected String coroutinesPackage; protected String coroutinesPackage = "";
protected ConfigurationKind configurationKind = ConfigurationKind.JDK_ONLY; protected ConfigurationKind configurationKind = ConfigurationKind.JDK_ONLY;
private final String defaultJvmTarget = System.getProperty(DEFAULT_JVM_TARGET_FOR_TEST); private final String defaultJvmTarget = System.getProperty(DEFAULT_JVM_TARGET_FOR_TEST);
@@ -99,7 +98,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
protected final void createEnvironmentWithMockJdkAndIdeaAnnotations( protected final void createEnvironmentWithMockJdkAndIdeaAnnotations(
@NotNull ConfigurationKind configurationKind, @NotNull ConfigurationKind configurationKind,
@Nullable File... javaSourceRoots @NotNull File... javaSourceRoots
) { ) {
createEnvironmentWithMockJdkAndIdeaAnnotations(configurationKind, Collections.emptyList(), TestJdkKind.MOCK_JDK, javaSourceRoots); createEnvironmentWithMockJdkAndIdeaAnnotations(configurationKind, Collections.emptyList(), TestJdkKind.MOCK_JDK, javaSourceRoots);
} }
@@ -118,7 +117,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
@NotNull ConfigurationKind configurationKind, @NotNull ConfigurationKind configurationKind,
@NotNull List<TestFile> testFilesWithConfigurationDirectives, @NotNull List<TestFile> testFilesWithConfigurationDirectives,
@NotNull TestJdkKind testJdkKind, @NotNull TestJdkKind testJdkKind,
@Nullable File... javaSourceRoots @NotNull File... javaSourceRoots
) { ) {
if (myEnvironment != null) { if (myEnvironment != null) {
throw new IllegalStateException("must not set up myEnvironment twice"); throw new IllegalStateException("must not set up myEnvironment twice");
@@ -161,7 +160,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
updateConfigurationByDirectivesInTestFiles(testFilesWithConfigurationDirectives, configuration, ""); updateConfigurationByDirectivesInTestFiles(testFilesWithConfigurationDirectives, configuration, "");
} }
protected static void updateConfigurationByDirectivesInTestFiles( private static void updateConfigurationByDirectivesInTestFiles(
@NotNull List<TestFile> testFilesWithConfigurationDirectives, @NotNull List<TestFile> testFilesWithConfigurationDirectives,
@NotNull CompilerConfiguration configuration, @NotNull CompilerConfiguration configuration,
@NotNull String coroutinesPackage @NotNull String coroutinesPackage
@@ -306,12 +305,6 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
} }
} }
@Override
protected void setUp() throws Exception {
coroutinesPackage = "";
super.setUp();
}
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {
myFiles = null; myFiles = null;
@@ -343,7 +336,8 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
assert myFiles == null : "Should not initialize myFiles twice"; assert myFiles == null : "Should not initialize myFiles twice";
myFiles = CodegenTestFiles.create(file.getName(), content, myEnvironment.getProject()); myFiles = CodegenTestFiles.create(file.getName(), content, myEnvironment.getProject());
return content; return content;
} catch (IOException e) { }
catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -512,44 +506,46 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
} }
@NotNull @NotNull
protected ClassFileFactory generateClassesInFile(boolean reportProblems) { private ClassFileFactory generateClassesInFile(boolean reportProblems) {
if (classFileFactory == null) { if (classFileFactory != null) return classFileFactory;
try {
GenerationState generationState = GenerationUtils.compileFiles(
myFiles.getPsiFiles(), myEnvironment, getClassBuilderFactory(),
new NoScopeRecordCliBindingTrace()
);
classFileFactory = generationState.getFactory();
if (verifyWithDex() && DxChecker.RUN_DX_CHECKER) { try {
DxChecker.check(classFileFactory); GenerationState generationState = GenerationUtils.compileFiles(
} myFiles.getPsiFiles(), myEnvironment, getClassBuilderFactory(),
new NoScopeRecordCliBindingTrace()
);
classFileFactory = generationState.getFactory();
if (verifyWithDex() && DxChecker.RUN_DX_CHECKER) {
DxChecker.check(classFileFactory);
} }
catch (TestsCompiletimeError e) { }
if (reportProblems) { catch (TestsCompiletimeError e) {
e.getOriginal().printStackTrace(); if (reportProblems) {
System.err.println("Generating instructions as text..."); e.getOriginal().printStackTrace();
try { System.err.println("Generating instructions as text...");
if (classFileFactory == null) { try {
System.err.println("Cannot generate text: exception was thrown during generation"); if (classFileFactory == null) {
} System.err.println("Cannot generate text: exception was thrown during generation");
else {
System.err.println(classFileFactory.createText());
}
} }
catch (Throwable e1) { else {
System.err.println("Exception thrown while trying to generate text, the actual exception follows:"); System.err.println(classFileFactory.createText());
e1.printStackTrace();
System.err.println("-----------------------------------------------------------------------------");
} }
System.err.println("See exceptions above");
} else {
System.err.println("Compilation failure");
} }
throw e; catch (Throwable e1) {
} catch (Throwable e) { System.err.println("Exception thrown while trying to generate text, the actual exception follows:");
throw new TestsCompilerError(e); e1.printStackTrace();
System.err.println("-----------------------------------------------------------------------------");
}
System.err.println("See exceptions above");
} }
else {
System.err.println("Compilation failure");
}
throw e;
}
catch (Throwable e) {
throw new TestsCompilerError(e);
} }
return classFileFactory; return classFileFactory;
} }
@@ -558,7 +554,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
return true; return true;
} }
protected static boolean verifyAllFilesWithAsm(ClassFileFactory factory, ClassLoader loader, boolean reportProblems) { private static boolean verifyAllFilesWithAsm(ClassFileFactory factory, ClassLoader loader, boolean reportProblems) {
boolean noErrors = true; boolean noErrors = true;
for (OutputFile file : ClassFileUtilsKt.getClassFiles(factory)) { for (OutputFile file : ClassFileUtilsKt.getClassFiles(factory)) {
noErrors &= verifyWithAsm(file, loader, reportProblems); noErrors &= verifyWithAsm(file, loader, reportProblems);
@@ -607,7 +603,8 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
Class<?> aClass = generateFacadeClass(); Class<?> aClass = generateFacadeClass();
try { try {
return findTheOnlyMethod(aClass); return findTheOnlyMethod(aClass);
} catch (Error e) { }
catch (Error e) {
System.out.println(generateToText()); System.out.println(generateToText());
throw e; throw e;
} }
@@ -618,22 +615,11 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
return findDeclaredMethodByName(generateFacadeClass(), name); return findDeclaredMethodByName(generateFacadeClass(), name);
} }
@NotNull
@SuppressWarnings("unchecked")
public Class<? extends Annotation> loadAnnotationClassQuietly(@NotNull String fqName) {
try {
return (Class<? extends Annotation>) initializedClassLoader.loadClass(fqName);
}
catch (ClassNotFoundException e) {
throw ExceptionUtilsKt.rethrow(e);
}
}
protected void updateConfiguration(@NotNull CompilerConfiguration configuration) { protected void updateConfiguration(@NotNull CompilerConfiguration configuration) {
} }
protected ClassBuilderFactory getClassBuilderFactory(){ protected ClassBuilderFactory getClassBuilderFactory() {
return ClassBuilderFactories.TEST; return ClassBuilderFactories.TEST;
} }
@@ -641,7 +627,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
} }
protected void setCustomDefaultJvmTarget(CompilerConfiguration configuration) { private void setCustomDefaultJvmTarget(CompilerConfiguration configuration) {
JvmTarget target = configuration.get(JVMConfigurationKeys.JVM_TARGET); JvmTarget target = configuration.get(JVMConfigurationKeys.JVM_TARGET);
if (target == null && defaultJvmTarget != null) { if (target == null && defaultJvmTarget != null) {
JvmTarget value = JvmTarget.fromString(defaultJvmTarget); JvmTarget value = JvmTarget.fromString(defaultJvmTarget);
@@ -663,8 +649,8 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
boolean reportProblems boolean reportProblems
) { ) {
configurationKind = extractConfigurationKind(files); configurationKind = extractConfigurationKind(files);
boolean loadAndroidAnnotations = files.stream().anyMatch(it -> boolean loadAndroidAnnotations = files.stream().anyMatch(
InTextDirectivesUtils.isDirectiveDefined(it.content, "ANDROID_ANNOTATIONS") it -> InTextDirectivesUtils.isDirectiveDefined(it.content, "ANDROID_ANNOTATIONS")
); );
List<String> javacOptions = extractJavacOptions(files); List<String> javacOptions = extractJavacOptions(files);
@@ -744,7 +730,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
return javacOptions; return javacOptions;
} }
protected void updateJavacOptions(List<String> javacOptions) { private void updateJavacOptions(List<String> javacOptions) {
if (javaCompilationTarget != null && !javacOptions.contains("-target")) { if (javaCompilationTarget != null && !javacOptions.contains("-target")) {
javacOptions.add("-source"); javacOptions.add("-source");
javacOptions.add(javaCompilationTarget); javacOptions.add(javaCompilationTarget);
@@ -832,9 +818,9 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
} }
protected void doMultiFileTest( protected void doMultiFileTest(
@NotNull File wholeFile, @NotNull File wholeFile,
@NotNull List<TestFile> files, @NotNull List<TestFile> files,
@Nullable File javaFilesDir @Nullable File javaFilesDir
) throws Exception { ) throws Exception {
throw new UnsupportedOperationException("Multi-file test cases are not supported in this test"); throw new UnsupportedOperationException("Multi-file test cases are not supported in this test");
} }
@@ -843,7 +829,7 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
throws IOException, InvocationTargetException, IllegalAccessException { throws IOException, InvocationTargetException, IllegalAccessException {
Class<?> aClass = getGeneratedClass(classLoader, className); Class<?> aClass = getGeneratedClass(classLoader, className);
Method method = getBoxMethodOrNull(aClass); Method method = getBoxMethodOrNull(aClass);
assertTrue("Can't find box method in " + aClass,method != null); assertNotNull("Can't find box method in " + aClass, method);
callBoxMethodAndCheckResult(classLoader, aClass, method); callBoxMethodAndCheckResult(classLoader, aClass, method);
} }
@@ -876,7 +862,8 @@ public abstract class CodegenTestCase extends KtUsefulTestCase {
List<URL> classPath = extractUrls(classLoader); List<URL> classPath = extractUrls(classLoader);
if (classLoader instanceof GeneratedClassLoader) { if (classLoader instanceof GeneratedClassLoader) {
File outDir = KotlinTestUtils.tmpDirForTest(this); File outDir = KotlinTestUtils.tmpDirForTest(this);
SimpleOutputFileCollection currentOutput = new SimpleOutputFileCollection(((GeneratedClassLoader) classLoader).getAllGeneratedFiles()); SimpleOutputFileCollection currentOutput =
new SimpleOutputFileCollection(((GeneratedClassLoader) classLoader).getAllGeneratedFiles());
writeAllTo(currentOutput, outDir); writeAllTo(currentOutput, outDir);
classPath.add(0, outDir.toURI().toURL()); classPath.add(0, outDir.toURI().toURL());
} }
@@ -127,7 +127,8 @@ public class CodegenTestFiles {
String[] values = valueString.split(" "); String[] values = valueString.split(" ");
scriptParameterValues.add(values); scriptParameterValues.add(values);
} else { }
else {
scriptParameterValues.add(ArrayUtil.EMPTY_STRING_ARRAY); scriptParameterValues.add(ArrayUtil.EMPTY_STRING_ARRAY);
} }
} }
@@ -39,15 +39,17 @@ import java.util.List;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class CodegenTestUtil { public class CodegenTestUtil {
private CodegenTestUtil() {} private CodegenTestUtil() {
}
@NotNull @NotNull
public static ClassFileFactory generateFiles(@NotNull KotlinCoreEnvironment environment, @NotNull CodegenTestFiles files) { public static ClassFileFactory generateFiles(@NotNull KotlinCoreEnvironment environment, @NotNull CodegenTestFiles files) {
return GenerationUtils.compileFiles(files.getPsiFiles(), environment).getFactory(); return GenerationUtils.compileFiles(files.getPsiFiles(), environment).getFactory();
} }
public static void assertThrows(@NotNull Method foo, @NotNull Class<? extends Throwable> exceptionClass, public static void assertThrows(
@Nullable Object instance, @NotNull Object... args) throws IllegalAccessException { @NotNull Method foo, @NotNull Class<? extends Throwable> exceptionClass, @Nullable Object instance, @NotNull Object... args
) throws IllegalAccessException {
boolean caught = false; boolean caught = false;
try { try {
foo.invoke(instance, args); foo.invoke(instance, args);
@@ -46,10 +46,6 @@ object GenerationUtils {
writeAllTo(output) writeAllTo(output)
} }
@JvmStatic
fun compileFile(ktFile: KtFile, environment: KotlinCoreEnvironment): ClassFileFactory =
compileFiles(listOf(ktFile), environment).factory
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
fun compileFiles( fun compileFiles(
@@ -35,7 +35,7 @@ object InlineTestUtil {
fun checkNoCallsToInline(outputFiles: Iterable<OutputFile>, sourceFiles: List<KtFile>) { fun checkNoCallsToInline(outputFiles: Iterable<OutputFile>, sourceFiles: List<KtFile>) {
val inlineInfo = obtainInlineInfo(outputFiles) val inlineInfo = obtainInlineInfo(outputFiles)
val inlineMethods = inlineInfo.inlineMethods val inlineMethods = inlineInfo.inlineMethods
assert(!inlineMethods.isEmpty()) { "There are no inline methods" } assert(inlineMethods.isNotEmpty()) { "There are no inline methods" }
val notInlinedCalls = checkInlineMethodNotInvoked(outputFiles, inlineMethods) val notInlinedCalls = checkInlineMethodNotInvoked(outputFiles, inlineMethods)
assert(notInlinedCalls.isEmpty()) { "All inline methods should be inlined but:\n" + notInlinedCalls.joinToString("\n") } assert(notInlinedCalls.isEmpty()) { "All inline methods should be inlined but:\n" + notInlinedCalls.joinToString("\n") }
@@ -48,7 +48,7 @@ object InlineTestUtil {
val notInlinedParameters = checkParametersInlined(outputFiles, inlineInfo, sourceFiles) val notInlinedParameters = checkParametersInlined(outputFiles, inlineInfo, sourceFiles)
assert(notInlinedParameters.isEmpty()) { assert(notInlinedParameters.isEmpty()) {
"All inline parameters should be inlined but:\n${notInlinedParameters.joinToString("\n")}\n" + "All inline parameters should be inlined but:\n${notInlinedParameters.joinToString("\n")}\n" +
"but if you have not inlined lambdas or anonymous objects enable NO_CHECK_LAMBDA_INLINING directive" "but if you have not inlined lambdas or anonymous objects enable NO_CHECK_LAMBDA_INLINING directive"
} }
} }
} }
@@ -61,7 +61,9 @@ object InlineTestUtil {
val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader) val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader)
val classVisitor = object : ClassVisitorWithName() { val classVisitor = object : ClassVisitorWithName() {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? { override fun visitMethod(
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
): MethodVisitor? {
if (name + desc in inlineFunctions) { if (name + desc in inlineFunctions) {
inlineMethods.add(MethodInfo(className, name, desc)) inlineMethods.add(MethodInfo(className, name, desc))
} }
@@ -70,7 +72,7 @@ object InlineTestUtil {
} }
ClassReader(file.asByteArray()).accept(classVisitor, 0) ClassReader(file.asByteArray()).accept(classVisitor, 0)
binaryClasses.put(classVisitor.className, binaryClass) binaryClasses[classVisitor.className] = binaryClass
} }
return InlineInfo(inlineMethods, binaryClasses) return InlineInfo(inlineMethods, binaryClasses)
@@ -84,9 +86,11 @@ object InlineTestUtil {
//if inline function creates anonymous object then do not try to check that all lambdas are inlined //if inline function creates anonymous object then do not try to check that all lambdas are inlined
val classVisitor = object : ClassVisitorWithName() { val classVisitor = object : ClassVisitorWithName() {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? { override fun visitMethod(
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
): MethodVisitor? {
if (name + desc in inlineFunctions) { if (name + desc in inlineFunctions) {
return object: MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) { return object : MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) {
override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) { override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) {
doLambdaInliningCheck = false doLambdaInliningCheck = false
} }
@@ -126,7 +130,9 @@ object InlineTestUtil {
return null return null
} }
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? { override fun visitMethod(
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
): MethodVisitor? {
if (skipMethodsOfThisClass) { if (skipMethodsOfThisClass) {
return null return null
} }
@@ -160,11 +166,13 @@ object InlineTestUtil {
return notInlined return notInlined
} }
private fun checkParametersInlined(outputFiles: Iterable<OutputFile>, inlineInfo: InlineInfo, sourceFiles: List<KtFile>): ArrayList<NotInlinedParameter> { private fun checkParametersInlined(
outputFiles: Iterable<OutputFile>, inlineInfo: InlineInfo, sourceFiles: List<KtFile>
): ArrayList<NotInlinedParameter> {
val skipMethods = val skipMethods =
sourceFiles.flatMap { sourceFiles.flatMap {
InTextDirectivesUtils.findLinesWithPrefixesRemoved(it.text, "// SKIP_INLINE_CHECK_IN: ") InTextDirectivesUtils.findLinesWithPrefixesRemoved(it.text, "// SKIP_INLINE_CHECK_IN: ")
}.toSet() }.toSet()
val inlinedMethods = inlineInfo.inlineMethods val inlinedMethods = inlineInfo.inlineMethods
val notInlinedParameters = ArrayList<NotInlinedParameter>() val notInlinedParameters = ArrayList<NotInlinedParameter>()
@@ -172,7 +180,9 @@ object InlineTestUtil {
if (!isClassOrPackagePartKind(loadBinaryClass(file))) continue if (!isClassOrPackagePartKind(loadBinaryClass(file))) continue
ClassReader(file.asByteArray()).accept(object : ClassVisitorWithName() { ClassReader(file.asByteArray()).accept(object : ClassVisitorWithName() {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?): MethodVisitor? { override fun visitMethod(
access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
): MethodVisitor? {
val declaration = MethodInfo(className, name, desc) val declaration = MethodInfo(className, name, desc)
//do not check anonymous object creation in inline functions and in package facades //do not check anonymous object creation in inline functions and in package facades
@@ -184,7 +194,7 @@ object InlineTestUtil {
return null return null
} }
return object: MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) { return object : MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) {
override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) { override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) {
val fromCall = MethodInfo(className, this.name, this.desc) val fromCall = MethodInfo(className, this.name, this.desc)
notInlinedParameters.add(NotInlinedParameter(owner, fromCall)) notInlinedParameters.add(NotInlinedParameter(owner, fromCall))
@@ -201,29 +211,27 @@ object InlineTestUtil {
if (classInternalName.startsWith("kotlin/jvm/internal/")) if (classInternalName.startsWith("kotlin/jvm/internal/"))
return true return true
return isClassOrPackagePartKind(inlineInfo.binaryClasses[classInternalName]!!) return isClassOrPackagePartKind(inlineInfo.binaryClasses.getValue(classInternalName))
} }
private fun isClassOrPackagePartKind(klass: KotlinJvmBinaryClass): Boolean { private fun isClassOrPackagePartKind(klass: KotlinJvmBinaryClass): Boolean {
return klass.classHeader.kind == KotlinClassHeader.Kind.CLASS && !klass.classId.isLocal return klass.classHeader.kind == KotlinClassHeader.Kind.CLASS && !klass.classId.isLocal
|| klass.classHeader.kind == KotlinClassHeader.Kind.FILE_FACADE /*single file facade equals to package part*/ || klass.classHeader.kind == KotlinClassHeader.Kind.FILE_FACADE /*single file facade equals to package part*/
|| klass.classHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART || klass.classHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
} }
private fun loadBinaryClass(file: OutputFile): KotlinJvmBinaryClass { private fun loadBinaryClass(file: OutputFile): KotlinJvmBinaryClass =
val klass = FileBasedKotlinClass.create(file.asByteArray()) { FileBasedKotlinClass.create<FileBasedKotlinClass>(file.asByteArray()) { className, classVersion, classHeader, innerClasses ->
className, classVersion, classHeader, innerClasses ->
object : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) { object : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) {
override val location: String override val location: String
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
override fun getFileContents(): ByteArray = throw UnsupportedOperationException() override fun getFileContents(): ByteArray = throw UnsupportedOperationException()
override fun hashCode(): Int = throw UnsupportedOperationException() override fun hashCode(): Int = throw UnsupportedOperationException()
override fun equals(other: Any?): Boolean = throw UnsupportedOperationException() override fun equals(other: Any?): Boolean = throw UnsupportedOperationException()
override fun toString(): String = throw UnsupportedOperationException() override fun toString(): String = throw UnsupportedOperationException()
} }
}!! }!!
return klass
}
private class InlineInfo(val inlineMethods: Set<MethodInfo>, val binaryClasses: Map<String, KotlinJvmBinaryClass>) private class InlineInfo(val inlineMethods: Set<MethodInfo>, val binaryClasses: Map<String, KotlinJvmBinaryClass>)
@@ -242,9 +250,11 @@ object InlineTestUtil {
} }
} }
private abstract class MethodNodeWithAnonymousObjectCheck(val inlineInfo: InlineInfo, access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?) : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) { private abstract class MethodNodeWithAnonymousObjectCheck(
val inlineInfo: InlineInfo, access: Int, name: String, desc: String, signature: String?, exceptions: Array<String>?
) : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) {
private fun isInlineParameterLikeOwner(owner: String) = private fun isInlineParameterLikeOwner(owner: String) =
"$" in owner && !isTopLevelOrInnerOrPackageClass(owner, inlineInfo) "$" in owner && !isTopLevelOrInnerOrPackageClass(owner, inlineInfo)
override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) { override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) {
if ("<init>" == name && isInlineParameterLikeOwner(owner)) { if ("<init>" == name && isInlineParameterLikeOwner(owner)) {
@@ -41,7 +41,7 @@ object SMAPTestUtil {
} }
}, 0) }, 0)
SMAPAndFile.SMAPAndFile(debugInfo, outputFile.sourceFiles.single(), outputFile.relativePath) SMAPAndFile(debugInfo, outputFile.sourceFiles.single(), outputFile.relativePath)
} }
} }
@@ -61,7 +61,10 @@ object SMAPTestUtil {
} }
private fun checkExtension(file: CodegenTestCase.TestFile, separateCompilation: Boolean) = private fun checkExtension(file: CodegenTestCase.TestFile, separateCompilation: Boolean) =
file.name.run { endsWith(".smap") || if (separateCompilation) endsWith(".smap-separate-compilation") else endsWith(".smap-nonseparate-compilation") } file.name.run {
endsWith(".smap") ||
if (separateCompilation) endsWith(".smap-separate-compilation") else endsWith(".smap-nonseparate-compilation")
}
fun checkSMAP(inputFiles: List<CodegenTestCase.TestFile>, outputFiles: Iterable<OutputFile>, separateCompilation: Boolean) { fun checkSMAP(inputFiles: List<CodegenTestCase.TestFile>, outputFiles: Iterable<OutputFile>, separateCompilation: Boolean) {
if (!GENERATE_SMAP) return if (!GENERATE_SMAP) return
@@ -71,15 +74,15 @@ object SMAPTestUtil {
val compiledData = compiledSmaps.groupBy { val compiledData = compiledSmaps.groupBy {
it.sourceFile it.sourceFile
}.map { }.map {
val smap = it.value.sortedByDescending { it.outputFile }.mapNotNull { it.smap }.joinToString("\n") val smap = it.value.sortedByDescending(SMAPAndFile::outputFile).mapNotNull(SMAPAndFile::smap).joinToString("\n")
SMAPAndFile(if (smap.isNotEmpty()) smap else null, it.key, "NOT_SORTED") SMAPAndFile(if (smap.isNotEmpty()) smap else null, it.key, "NOT_SORTED")
}.associateBy { it.sourceFile } }.associateBy { it.sourceFile }
for (source in sourceData) { for (source in sourceData) {
val ktFileName = "/" + source.sourceFile. val ktFileName = "/" + source.sourceFile
replace(".smap-nonseparate-compilation", ".kt"). .replace(".smap-nonseparate-compilation", ".kt")
replace(".smap-separate-compilation", ".kt"). .replace(".smap-separate-compilation", ".kt")
replace(".smap", ".kt") .replace(".smap", ".kt")
val data = compiledData[ktFileName] val data = compiledData[ktFileName]
Assert.assertEquals("Smap data differs for $ktFileName", normalize(source.smap), normalize(data?.smap)) Assert.assertEquals("Smap data differs for $ktFileName", normalize(source.smap), normalize(data?.smap))
} }
@@ -90,37 +93,32 @@ object SMAPTestUtil {
private fun checkNoConflictMappings(compiledSmap: List<SMAPAndFile>?) { private fun checkNoConflictMappings(compiledSmap: List<SMAPAndFile>?) {
if (compiledSmap == null) return if (compiledSmap == null) return
compiledSmap.mapNotNull { it.smap }.forEach { compiledSmap.mapNotNull(SMAPAndFile::smap).forEach { smapString ->
val smap = SMAPParser.parse(it) val smap = SMAPParser.parse(smapString)
val conflictingLines = smap.fileMappings.flatMap { val conflictingLines = smap.fileMappings.flatMap { fileMapping ->
fileMapping -> fileMapping.lineMappings.flatMap { lineMapping: RangeMapping ->
fileMapping.lineMappings.flatMap {
lineMapping: RangeMapping ->
lineMapping.toRange.keysToMap { lineMapping }.entries lineMapping.toRange.keysToMap { lineMapping }.entries
} }
}.groupBy { it.key }.entries.filter { it.value.size != 1 } }.groupBy { it.key }.entries.filter { it.value.size != 1 }
Assert.assertTrue( Assert.assertTrue(
conflictingLines.joinToString(separator = "\n") { conflictingLines.joinToString(separator = "\n") {
"Conflicting mapping for line ${it.key} in ${it.value.joinToString { it.toString() }} " "Conflicting mapping for line ${it.key} in ${it.value.joinToString(transform = Any::toString)}"
}, },
conflictingLines.isEmpty() conflictingLines.isEmpty()
) )
} }
} }
private fun normalize(text: String?) = private fun normalize(text: String?) =
text?.let { StringUtil.convertLineSeparators(it.trim()) } text?.let { StringUtil.convertLineSeparators(it.trim()) }
private class SMAPAndFile(val smap: String?, val sourceFile: String, val outputFile: String) { private class SMAPAndFile(val smap: String?, val sourceFile: String, val outputFile: String) {
companion object { constructor(smap: String?, sourceFile: File, outputFile: String) : this(smap, getPath(sourceFile), outputFile)
fun SMAPAndFile(smap: String?, sourceFile: File, outputFile: String) =
SMAPAndFile(smap, getPath(sourceFile), outputFile)
fun getPath(file: File): String { companion object {
return getPath(file.canonicalPath) fun getPath(file: File): String =
} getPath(file.canonicalPath)
fun getPath(canonicalPath: String): String { fun getPath(canonicalPath: String): String {
//There are some problems with disk name on windows cause LightVirtualFile return it without disk name //There are some problems with disk name on windows cause LightVirtualFile return it without disk name
@@ -20,6 +20,6 @@ import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JVMConfigurationKeys
abstract class AbstractIrBlackBoxInlineCodegenTest: AbstractBlackBoxCodegenTest() { abstract class AbstractIrBlackBoxInlineCodegenTest : AbstractBlackBoxCodegenTest() {
override fun updateConfiguration(configuration: CompilerConfiguration) = configuration.put(JVMConfigurationKeys.IR, true) override fun updateConfiguration(configuration: CompilerConfiguration) = configuration.put(JVMConfigurationKeys.IR, true)
} }
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import junit.framework.TestCase
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.utils.rethrow
import java.lang.reflect.Method
import java.net.URL import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
@@ -28,17 +25,13 @@ fun clearReflectionCache(classLoader: ClassLoader) {
val klass = classLoader.loadClass(JvmAbi.REFLECTION_FACTORY_IMPL.asSingleFqName().asString()) val klass = classLoader.loadClass(JvmAbi.REFLECTION_FACTORY_IMPL.asSingleFqName().asString())
val method = klass.getDeclaredMethod("clearCaches") val method = klass.getDeclaredMethod("clearCaches")
method.invoke(null) method.invoke(null)
} } catch (e: ClassNotFoundException) {
catch (e: ClassNotFoundException) {
// This is OK for a test without kotlin-reflect in the dependencies // This is OK for a test without kotlin-reflect in the dependencies
} }
} }
fun ClassLoader?.extractUrls(): List<URL> { fun ClassLoader?.extractUrls(): List<URL> {
return (this as? URLClassLoader)?.let { return (this as? URLClassLoader)?.let {
it.urLs.toList() + it.parent.extractUrls() it.urLs.toList() + it.parent.extractUrls()
} ?: emptyList() } ?: emptyList()
}
}
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.script.loadScriptingPlugin
import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContextOrStlib
import org.jetbrains.kotlin.scripting.configuration.configureScriptDefinitions import org.jetbrains.kotlin.scripting.configuration.configureScriptDefinitions
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
@@ -25,6 +24,7 @@ import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.ScriptCompilationConfiguration
import kotlin.script.experimental.api.implicitReceivers import kotlin.script.experimental.api.implicitReceivers
import kotlin.script.experimental.api.providedProperties import kotlin.script.experimental.api.providedProperties
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrStdlib
abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() {
private lateinit var scriptDefinitions: List<String> private lateinit var scriptDefinitions: List<String>
@@ -56,14 +56,14 @@ abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() {
scriptDefinitions = InTextDirectivesUtils.findListWithPrefixes(content, "KOTLIN_SCRIPT_DEFINITION:") scriptDefinitions = InTextDirectivesUtils.findListWithPrefixes(content, "KOTLIN_SCRIPT_DEFINITION:")
if (scriptDefinitions.isNotEmpty()) { if (scriptDefinitions.isNotEmpty()) {
additionalDependencies = additionalDependencies =
scriptCompilationClasspathFromContextOrStlib("tests-common", "kotlin-stdlib") + scriptCompilationClasspathFromContextOrStdlib("tests-common", "kotlin-stdlib") +
File(TestScriptWithReceivers::class.java.protectionDomain.codeSource.location.toURI().path) + File(TestScriptWithReceivers::class.java.protectionDomain.codeSource.location.toURI().path) +
with(PathUtil.kotlinPathsForDistDirectory) { with(PathUtil.kotlinPathsForDistDirectory) {
arrayOf( arrayOf(
KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMPILER_IMPL_JAR, KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMPILER_IMPL_JAR,
KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR
).mapNotNull { File(libPath, it).takeIf { it.exists() } } ).mapNotNull { File(libPath, it).takeIf(File::exists) }
} }
} }
createEnvironmentWithMockJdkAndIdeaAnnotations(configurationKind, files, TestJdkKind.FULL_JDK) createEnvironmentWithMockJdkAndIdeaAnnotations(configurationKind, files, TestJdkKind.FULL_JDK)
@@ -71,7 +71,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(getDeprecatedAnnotationFromList(srcClassMethod.getParameterAnnotations()[0])); assertNotNull(getDeprecatedAnnotationFromList(srcClassMethod.getParameterAnnotations()[0]));
} }
public void testAnnotationForParamInInstanceFunction() throws NoSuchFieldException, NoSuchMethodException { public void testAnnotationForParamInInstanceFunction() throws NoSuchMethodException {
loadText("class A() { fun x(@[java.lang.Deprecated] i: Int) {}}"); loadText("class A() { fun x(@[java.lang.Deprecated] i: Int) {}}");
Class<?> aClass = generateClass("A"); Class<?> aClass = generateClass("A");
Method x = aClass.getMethod("x", int.class); Method x = aClass.getMethod("x", int.class);
@@ -81,7 +81,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(getDeprecatedAnnotationFromList(annotations)); assertNotNull(getDeprecatedAnnotationFromList(annotations));
} }
public void testAnnotationForParamInInstanceExtensionFunction() throws NoSuchFieldException, NoSuchMethodException { public void testAnnotationForParamInInstanceExtensionFunction() throws NoSuchMethodException {
loadText("class A() { fun String.x(@[java.lang.Deprecated] i: Int) {}}"); loadText("class A() { fun String.x(@[java.lang.Deprecated] i: Int) {}}");
Class<?> aClass = generateClass("A"); Class<?> aClass = generateClass("A");
Method x = aClass.getMethod("x", String.class, int.class); Method x = aClass.getMethod("x", String.class, int.class);
@@ -91,7 +91,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(getDeprecatedAnnotationFromList(annotations)); assertNotNull(getDeprecatedAnnotationFromList(annotations));
} }
public void testParamInConstructor() throws NoSuchFieldException, NoSuchMethodException { public void testParamInConstructor() throws NoSuchMethodException {
loadText("class A (@[java.lang.Deprecated] x: Int) {}"); loadText("class A (@[java.lang.Deprecated] x: Int) {}");
Class<?> aClass = generateClass("A"); Class<?> aClass = generateClass("A");
Constructor constructor = aClass.getDeclaredConstructor(int.class); Constructor constructor = aClass.getDeclaredConstructor(int.class);
@@ -101,7 +101,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(getDeprecatedAnnotationFromList(annotations)); assertNotNull(getDeprecatedAnnotationFromList(annotations));
} }
public void testParamInEnumConstructor() throws NoSuchFieldException, NoSuchMethodException { public void testParamInEnumConstructor() throws NoSuchMethodException {
loadText("enum class E(@[java.lang.Deprecated] p: String)"); loadText("enum class E(@[java.lang.Deprecated] p: String)");
Class<?> klass = generateClass("E"); Class<?> klass = generateClass("E");
Constructor constructor = klass.getDeclaredConstructor(String.class, int.class, String.class); Constructor constructor = klass.getDeclaredConstructor(String.class, int.class, String.class);
@@ -111,7 +111,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(getDeprecatedAnnotationFromList(annotations)); assertNotNull(getDeprecatedAnnotationFromList(annotations));
} }
public void testParamInInnerConstructor() throws NoSuchFieldException, NoSuchMethodException { public void testParamInInnerConstructor() throws NoSuchMethodException {
loadText("class Outer { inner class Inner(@[java.lang.Deprecated] x: Int) }"); loadText("class Outer { inner class Inner(@[java.lang.Deprecated] x: Int) }");
Class<?> outer = generateClass("Outer"); Class<?> outer = generateClass("Outer");
Class<?> inner = outer.getDeclaredClasses()[0]; Class<?> inner = outer.getDeclaredClasses()[0];
@@ -134,7 +134,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNull(aClass.getDeclaredMethod("setX", int.class).getAnnotation(Deprecated.class)); assertNull(aClass.getDeclaredMethod("setX", int.class).getAnnotation(Deprecated.class));
assertNotNull(aClass.getDeclaredField("x").getAnnotation(Deprecated.class)); assertNotNull(aClass.getDeclaredField("x").getAnnotation(Deprecated.class));
} }
public void testAnnotationWithParamForParamInFunction() throws Exception { public void testAnnotationWithParamForParamInFunction() throws Exception {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" + "@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" +
@@ -162,7 +162,7 @@ public class AnnotationGenTest extends CodegenTestCase {
} }
} }
return null; return null;
} }
public void testConstructor() throws NoSuchFieldException, NoSuchMethodException { public void testConstructor() throws NoSuchFieldException, NoSuchMethodException {
loadText("class A @[java.lang.Deprecated] constructor() {}"); loadText("class A @[java.lang.Deprecated] constructor() {}");
@@ -196,14 +196,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertEquals("java.lang.annotation.Annotation", interfaces[0].getName()); assertEquals("java.lang.annotation.Annotation", interfaces[0].getName());
} }
public void testAnnotationClassWithStringProperty() public void testAnnotationClassWithStringProperty() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
throws
NoSuchFieldException,
NoSuchMethodException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"" + "" +
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" + "@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" +
@@ -231,13 +224,7 @@ public class AnnotationGenTest extends CodegenTestCase {
} }
public void testAnnotationClassWithAnnotationProperty() public void testAnnotationClassWithAnnotationProperty()
throws throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException {
NoSuchFieldException,
NoSuchMethodException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"" + "" +
"annotation class C(val c: String)\n" + "annotation class C(val c: String)\n" +
@@ -270,13 +257,7 @@ public class AnnotationGenTest extends CodegenTestCase {
} }
public void testAnnotationClassWithStringArrayProperty() public void testAnnotationClassWithStringArrayProperty()
throws throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
NoSuchFieldException,
NoSuchMethodException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"" + "" +
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: Array<String>)\n" + "@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: Array<String>)\n" +
@@ -301,18 +282,11 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(bClassAnnotation); assertNotNull(bClassAnnotation);
Object invoke = methods[0].invoke(bClassAnnotation); Object invoke = methods[0].invoke(bClassAnnotation);
assertEquals("239", ((String[])invoke)[0]); assertEquals("239", ((String[]) invoke)[0]);
assertEquals("932", ((String[])invoke)[1]); assertEquals("932", ((String[]) invoke)[1]);
} }
public void testAnnotationClassWithIntArrayProperty() public void testAnnotationClassWithIntArrayProperty() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
throws
NoSuchFieldException,
NoSuchMethodException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"" + "" +
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: IntArray)\n" + "@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: IntArray)\n" +
@@ -337,18 +311,11 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(bClassAnnotation); assertNotNull(bClassAnnotation);
Object invoke = methods[0].invoke(bClassAnnotation); Object invoke = methods[0].invoke(bClassAnnotation);
assertEquals(239, ((int[])invoke)[0]); assertEquals(239, ((int[]) invoke)[0]);
assertEquals(932, ((int[])invoke)[1]); assertEquals(932, ((int[]) invoke)[1]);
} }
public void testAnnotationClassWithEnumArrayProperty() public void testAnnotationClassWithEnumArrayProperty() {
throws
NoSuchFieldException,
NoSuchMethodException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"" + "" +
"@java.lang.annotation.Target(ElementType.TYPE, ElementType.METHOD) annotation class A"); "@java.lang.annotation.Target(ElementType.TYPE, ElementType.METHOD) annotation class A");
@@ -363,13 +330,7 @@ public class AnnotationGenTest extends CodegenTestCase {
} }
public void testAnnotationClassWithAnnotationArrayProperty() public void testAnnotationClassWithAnnotationArrayProperty()
throws throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
NoSuchFieldException,
NoSuchMethodException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException,
InvocationTargetException {
loadText("import java.lang.annotation.*\n" + loadText("import java.lang.annotation.*\n" +
"import java.lang.annotation.Retention\n" + "import java.lang.annotation.Retention\n" +
"" + "" +
@@ -388,7 +349,7 @@ public class AnnotationGenTest extends CodegenTestCase {
assertNotNull(bClassAnnotation); assertNotNull(bClassAnnotation);
Object invoke = methods[0].invoke(bClassAnnotation); Object invoke = methods[0].invoke(bClassAnnotation);
Retention[] invoke1 = (Retention[])invoke; Retention[] invoke1 = (Retention[]) invoke;
assertEquals(2, invoke1.length); assertEquals(2, invoke1.length);
assertEquals(invoke1[0].value(), RetentionPolicy.RUNTIME); assertEquals(invoke1[0].value(), RetentionPolicy.RUNTIME);
assertEquals(invoke1[1].value(), RetentionPolicy.SOURCE); assertEquals(invoke1[1].value(), RetentionPolicy.SOURCE);
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.backend.common.bridges.Bridge
import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle
import org.jetbrains.kotlin.backend.common.bridges.generateBridges import org.jetbrains.kotlin.backend.common.bridges.generateBridges
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
import java.util.*
import kotlin.test.assertEquals import kotlin.test.assertEquals
class BridgeTest : TestCase() { class BridgeTest : TestCase() {
@@ -91,14 +90,14 @@ class BridgeTest : TestCase() {
return result return result
} }
val vertices = edges.flatMapTo(HashSet<Fun>()) { pair -> listOf(pair.first, pair.second) } val vertices = edges.flatMapTo(HashSet()) { pair -> listOf(pair.first, pair.second) }
for (vertex in vertices) { for (vertex in vertices) {
val directConcreteSuperFunctions = vertex.overriddenFunctions.filter { !it.isAbstract } val directConcreteSuperFunctions = vertex.overriddenFunctions.filter { !it.isAbstract }
assert(directConcreteSuperFunctions.size <= 1) { assert(directConcreteSuperFunctions.size <= 1) {
"Incorrect test data: function $vertex has more than one direct concrete super-function: ${vertex.overriddenFunctions}\n" + "Incorrect test data: function $vertex has more than one direct concrete super-function: ${vertex.overriddenFunctions}\n" +
"This is not allowed because only classes can contain implementations (concrete functions), and having more than one " + "This is not allowed because only classes can contain implementations (concrete functions), and having more than " +
"concrete super-function means having more than one superclass, which is prohibited in Kotlin" "one concrete super-function means having more than one superclass, which is prohibited in Kotlin"
} }
if (vertex.isDeclaration) continue if (vertex.isDeclaration) continue
@@ -120,7 +119,7 @@ class BridgeTest : TestCase() {
} }
assert(concreteDeclarations.size == 1) { assert(concreteDeclarations.size == 1) {
"Incorrect test data: concrete fake override vertex $vertex has more than one concrete super-declaration: " + "Incorrect test data: concrete fake override vertex $vertex has more than one concrete super-declaration: " +
"$concreteDeclarations" "$concreteDeclarations"
} }
} }
} }
@@ -130,7 +129,7 @@ class BridgeTest : TestCase() {
val actualBridges = generateBridges(function, ::Meth) val actualBridges = generateBridges(function, ::Meth)
assert(actualBridges.firstOrNull { it.from == it.to } == null) { assert(actualBridges.firstOrNull { it.from == it.to } == null) {
"A bridge invoking itself was generated, which makes no sense, since it will result in StackOverflowError" + "A bridge invoking itself was generated, which makes no sense, since it will result in StackOverflowError" +
" once called: $actualBridges" " once called: $actualBridges"
} }
assertEquals(expectedBridges, actualBridges, "Expected and actual bridge sets differ for function $function") assertEquals(expectedBridges, actualBridges, "Expected and actual bridge sets differ for function $function")
} }
@@ -537,9 +536,11 @@ class BridgeTest : TestCase() {
val h = v("-D8") val h = v("-D8")
val i = v("-D9") val i = v("-D9")
val j = v("+F0") val j = v("+F0")
graph(d to a, d to b, d to c, graph(
g to d, g to e, g to f, d to a, d to b, d to c,
j to g, j to h, j to i) g to d, g to e, g to f,
j to g, j to h, j to i
)
doTest(d, setOf(bridge(b, a), bridge(c, a))) doTest(d, setOf(bridge(b, a), bridge(c, a)))
doTest(g, setOf(bridge(e, a), bridge(f, a))) doTest(g, setOf(bridge(e, a), bridge(f, a)))
doTest(j, setOf(bridge(h, a), bridge(i, a))) doTest(j, setOf(bridge(h, a), bridge(i, a)))
@@ -68,7 +68,7 @@ public class ControlStructuresTest extends CodegenTestCase {
public void testCompareToNull() throws Exception { public void testCompareToNull() throws Exception {
loadText("fun foo(a: String?, b: String?): Boolean = a == null && b !== null && null == a && null !== b"); loadText("fun foo(a: String?, b: String?): Boolean = a == null && b !== null && null == a && null !== b");
String text = generateToText(); String text = generateToText();
assertTrue(!text.contains("java/lang/Object.equals")); assertFalse(text.contains("java/lang/Object.equals"));
Method main = generateFunction(); Method main = generateFunction();
assertEquals(true, main.invoke(null, null, "lala")); assertEquals(true, main.invoke(null, null, "lala"));
assertEquals(false, main.invoke(null, null, null)); assertEquals(false, main.invoke(null, null, null));
@@ -22,29 +22,35 @@ import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
class CustomBytecodeTextTest : AbstractBytecodeTextTest() { class CustomBytecodeTextTest : AbstractBytecodeTextTest() {
fun testEnumMapping() { fun testEnumMapping() {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL) createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL)
myFiles = CodegenTestFiles.create("whenMappingOrder.kt", """ myFiles = CodegenTestFiles.create(
enum class MyEnum { "whenMappingOrder.kt",
ENTRY1, ENTRY2, ENTRY3, ENTRY4 """
} enum class MyEnum {
ENTRY1, ENTRY2, ENTRY3, ENTRY4
fun f(e: MyEnum) {
when (e) {
MyEnum.ENTRY4 -> {}
MyEnum.ENTRY3 -> {}
MyEnum.ENTRY2 -> {}
MyEnum.ENTRY1 -> {}
} }
}
""", myEnvironment.project) fun f(e: MyEnum) {
when (e) {
MyEnum.ENTRY4 -> {}
MyEnum.ENTRY3 -> {}
MyEnum.ENTRY2 -> {}
MyEnum.ENTRY1 -> {}
}
}
""",
myEnvironment.project
)
val text = generateToText() val text = generateToText()
val getstatics = text.lines().filter { it.contains("GETSTATIC MyEnum.") }.map { it.trim() } val getstatics = text.lines().filter { it.contains("GETSTATIC MyEnum.") }.map { it.trim() }
KtUsefulTestCase.assertOrderedEquals("actual bytecode:\n" + text, listOf( KtUsefulTestCase.assertOrderedEquals(
"actual bytecode:\n$text", listOf(
"GETSTATIC MyEnum.${'$'}VALUES : [LMyEnum;", "GETSTATIC MyEnum.${'$'}VALUES : [LMyEnum;",
"GETSTATIC MyEnum.ENTRY4 : LMyEnum;", "GETSTATIC MyEnum.ENTRY4 : LMyEnum;",
"GETSTATIC MyEnum.ENTRY3 : LMyEnum;", "GETSTATIC MyEnum.ENTRY3 : LMyEnum;",
"GETSTATIC MyEnum.ENTRY2 : LMyEnum;", "GETSTATIC MyEnum.ENTRY2 : LMyEnum;",
"GETSTATIC MyEnum.ENTRY1 : LMyEnum;" "GETSTATIC MyEnum.ENTRY1 : LMyEnum;"
), getstatics) ), getstatics
)
} }
} }
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.script.loadScriptingPlugin
import org.jetbrains.kotlin.script.util.scriptCompilationClasspathFromContextOrStlib
import org.jetbrains.kotlin.scripting.configuration.configureScriptDefinitions import org.jetbrains.kotlin.scripting.configuration.configureScriptDefinitions
import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
@@ -19,9 +18,10 @@ import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMPILER_IMPL_JAR
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR
import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR import org.jetbrains.kotlin.utils.PathUtil.KOTLIN_SCRIPTING_JVM_JAR
import java.io.File import java.io.File
import java.lang.reflect.Constructor
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.annotations.KotlinScript
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrStdlib
class CustomScriptCodegenTest : CodegenTestCase() { class CustomScriptCodegenTest : CodegenTestCase() {
@@ -46,14 +46,14 @@ class CustomScriptCodegenTest : CodegenTestCase() {
} }
additionalDependencies = additionalDependencies =
scriptCompilationClasspathFromContextOrStlib("tests-common", "kotlin-stdlib") + scriptCompilationClasspathFromContextOrStdlib("tests-common", "kotlin-stdlib") +
File(TestScriptWithReceivers::class.java.protectionDomain.codeSource.location.toURI().path) + File(TestScriptWithReceivers::class.java.protectionDomain.codeSource.location.toURI().path) +
with(PathUtil.kotlinPathsForDistDirectory) { with(PathUtil.kotlinPathsForDistDirectory) {
arrayOf( arrayOf(
KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMPILER_IMPL_JAR, KOTLIN_SCRIPTING_COMPILER_PLUGIN_JAR, KOTLIN_SCRIPTING_COMPILER_IMPL_JAR,
KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR KOTLIN_SCRIPTING_COMMON_JAR, KOTLIN_SCRIPTING_JVM_JAR
).mapNotNull { File(libPath, it).also { assertTrue("$it not found", it.exists()) } } ).mapNotNull { jarName -> File(libPath, jarName).also { assertTrue("$it not found", it.exists()) } }
} }
val configuration = createConfiguration( val configuration = createConfiguration(
ConfigurationKind.ALL, ConfigurationKind.ALL,
@@ -75,7 +75,6 @@ class CustomScriptCodegenTest : CodegenTestCase() {
testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES
) )
} }
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -83,7 +82,7 @@ private fun Class<*>.safeGetAnnotation(ann: KClass<out Annotation>): Annotation?
getAnnotation(classLoader.loadClass(ann.qualifiedName) as Class<Annotation>) getAnnotation(classLoader.loadClass(ann.qualifiedName) as Class<Annotation>)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun java.lang.reflect.Constructor<*>.safeGetAnnotation(ann: KClass<out Annotation>): Annotation? = private fun Constructor<*>.safeGetAnnotation(ann: KClass<out Annotation>): Annotation? =
getAnnotation(this.declaringClass.classLoader.loadClass(ann.qualifiedName) as Class<Annotation>) getAnnotation(this.declaringClass.classLoader.loadClass(ann.qualifiedName) as Class<Annotation>)
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
@@ -96,6 +95,5 @@ annotation class MyScriptConstructorAnnotation
@Suppress("unused") @Suppress("unused")
@KotlinScript @KotlinScript
@MyScriptClassAnnotation() @MyScriptClassAnnotation
abstract class TestScriptWithAnnotatedBaseClass @MyScriptConstructorAnnotation constructor() abstract class TestScriptWithAnnotatedBaseClass @MyScriptConstructorAnnotation constructor()
@@ -55,7 +55,8 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, disableCallAssertions); configuration.put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, disableCallAssertions);
configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, disableParamAssertions); configuration.put(JVMConfigurationKeys.DISABLE_PARAM_ASSERTIONS, disableParamAssertions);
myEnvironment = KotlinCoreEnvironment.createForTests(getTestRootDisposable(), configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); myEnvironment =
KotlinCoreEnvironment.createForTests(getTestRootDisposable(), configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES);
myFiles = null; myFiles = null;
} }
@@ -87,7 +88,7 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
doTestCallAssertions(true); doTestCallAssertions(true);
} }
public void testNoAssertionsForKotlinFromSource() throws Exception { public void testNoAssertionsForKotlinFromSource() {
setUpEnvironment(false, true); setUpEnvironment(false, true);
loadFiles(getPrefix() + "/noAssertionsForKotlin.kt", getPrefix() + "/noAssertionsForKotlinMain.kt"); loadFiles(getPrefix() + "/noAssertionsForKotlin.kt", getPrefix() + "/noAssertionsForKotlinMain.kt");
@@ -95,7 +96,7 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
assertNoIntrinsicsMethodIsCalledInMyClasses(true); assertNoIntrinsicsMethodIsCalledInMyClasses(true);
} }
public void testNoAssertionsForKotlinFromBinary() throws Exception { public void testNoAssertionsForKotlinFromBinary() {
setUpEnvironment(false, true); setUpEnvironment(false, true);
loadSource("noAssertionsForKotlin.kt"); loadSource("noAssertionsForKotlin.kt");
OutputFileCollection outputFiles = generateClassesInFile(); OutputFileCollection outputFiles = generateClassesInFile();
@@ -116,7 +117,7 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
generateFunction().invoke(null); generateFunction().invoke(null);
} }
public void testDoNotGenerateParamAssertions() throws Exception { public void testDoNotGenerateParamAssertions() {
setUpEnvironment(true, true); setUpEnvironment(true, true);
loadSource("doNotGenerateParamAssertions.kt"); loadSource("doNotGenerateParamAssertions.kt");
@@ -124,7 +125,7 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase {
assertNoIntrinsicsMethodIsCalled("A", true); assertNoIntrinsicsMethodIsCalled("A", true);
} }
public void testNoParamAssertionForPrivateMethod() throws Exception { public void testNoParamAssertionForPrivateMethod() {
setUpEnvironment(true, false); setUpEnvironment(true, false);
loadSource("noAssertionForPrivateMethod.kt"); loadSource("noAssertionForPrivateMethod.kt");
@@ -116,8 +116,6 @@ public class InnerClassInfoGenTest extends CodegenTestCase {
extractAndCompareInnerClasses("A$bar$1", bar); extractAndCompareInnerClasses("A$bar$1", bar);
} }
private void checkAccess(@NotNull String outerName, @NotNull String innerName, int accessFlags) { private void checkAccess(@NotNull String outerName, @NotNull String innerName, int accessFlags) {
String name = outerName + "$" + innerName; String name = outerName + "$" + innerName;
InnerClassAttribute attribute = CollectionsKt.single(extractInnerClasses(name), value -> innerName.equals(value.innerName)); InnerClassAttribute attribute = CollectionsKt.single(extractInnerClasses(name), value -> innerName.equals(value.innerName));
@@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit
class Java9CodegenTest : AbstractBlackBoxCodegenTest() { class Java9CodegenTest : AbstractBlackBoxCodegenTest() {
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
val fileName = KotlinTestUtils.getTestDataPathBase() + "/codegen/" + getPrefix() + "/" + getTestName(true) + ".kt" val fileName = KotlinTestUtils.getTestDataPathBase() + "/codegen/" + prefix + "/" + getTestName(true) + ".kt"
val testFile = TestFile(fileName, File(fileName).readText()) val testFile = TestFile(fileName, File(fileName).readText())
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.NO_KOTLIN_REFLECT, listOf(testFile), TestJdkKind.FULL_JDK_9) createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.NO_KOTLIN_REFLECT, listOf(testFile), TestJdkKind.FULL_JDK_9)
} }
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion; import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Collection; import java.util.Collection;
@@ -32,7 +33,7 @@ import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.METADATA_FQ_NAME
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.METADATA_VERSION_FIELD_NAME; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.METADATA_VERSION_FIELD_NAME;
public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
public static final FqName PACKAGE_NAME = new FqName("test"); private static final FqName PACKAGE_NAME = new FqName("test");
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
@@ -124,7 +125,7 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
List<OutputFile> output = generateClassesInFile().asList(); List<OutputFile> output = generateClassesInFile().asList();
Collection<OutputFile> files = CollectionsKt.filter(output, file -> file.getRelativePath().contains(classFilePart)); Collection<OutputFile> files = CollectionsKt.filter(output, file -> file.getRelativePath().contains(classFilePart));
assertFalse("No files with \"" + classFilePart + "\" in the name are found: " + output, files.isEmpty()); assertFalse("No files with \"" + classFilePart + "\" in the name are found: " + output, files.isEmpty());
assertTrue("Exactly one file with \"" + classFilePart + "\" in the name should be found: " + files, files.size() == 1); assertEquals("Exactly one file with \"" + classFilePart + "\" in the name should be found: " + files, 1, files.size());
String path = files.iterator().next().getRelativePath(); String path = files.iterator().next().getRelativePath();
String fqName = path.substring(0, path.length() - ".class".length()).replace('/', '.'); String fqName = path.substring(0, path.length() - ".class".length()).replace('/', '.');
@@ -144,4 +145,15 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
assertTrue("Annotation " + annotationFqName + " is written with an unsupported format", assertTrue("Annotation " + annotationFqName + " is written with an unsupported format",
new JvmMetadataVersion(version).isCompatible()); new JvmMetadataVersion(version).isCompatible());
} }
@NotNull
@SuppressWarnings("unchecked")
private Class<? extends Annotation> loadAnnotationClassQuietly(@NotNull String fqName) {
try {
return (Class<? extends Annotation>) initializedClassLoader.loadClass(fqName);
}
catch (ClassNotFoundException e) {
throw ExceptionUtilsKt.rethrow(e);
}
}
} }
@@ -24,111 +24,126 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import java.util.* import java.util.*
class MethodOrderTest: CodegenTestCase() { class MethodOrderTest : CodegenTestCase() {
fun testDelegatedMethod() { fun testDelegatedMethod() {
doTest( doTest(
""" """
interface Trait { interface Trait {
fun f0() fun f0()
fun f4() fun f4()
fun f3() fun f3()
fun f2() fun f2()
fun f1() fun f1()
fun f5() fun f5()
} }
val delegate: Trait = throw Error() val delegate: Trait = throw Error()
val obj = object : Trait by delegate { val obj = object : Trait by delegate {
override fun f3() { } override fun f3() { }
} }
""", """,
"\$obj$1", "\$obj$1",
listOf("f3()V", "<init>()V", "f0()V", "f1()V", "f2()V", "f4()V", "f5()V") listOf("f3()V", "<init>()V", "f0()V", "f1()V", "f2()V", "f4()V", "f5()V")
) )
} }
fun testLambdaClosureOrdering() { fun testLambdaClosureOrdering() {
doTest( doTest(
""" """
class Klass { class Klass {
fun Any.f(a: String, b: Int, c: Double, d: Any, e: Long) { fun Any.f(a: String, b: Int, c: Double, d: Any, e: Long) {
{ a + b + c + d + e + this@f + this@Klass }() { a + b + c + d + e + this@f + this@Klass }()
}
} }
""", }
"\$f$1", """,
listOf("invoke()Ljava/lang/Object;", "invoke()Ljava/lang/String;", "<init>(LKlass;Ljava/lang/Object;Ljava/lang/String;IDLjava/lang/Object;J)V") "\$f$1",
listOf(
"invoke()Ljava/lang/Object;",
"invoke()Ljava/lang/String;",
"<init>(LKlass;Ljava/lang/Object;Ljava/lang/String;IDLjava/lang/Object;J)V"
)
) )
} }
fun testAnonymousObjectClosureOrdering() { fun testAnonymousObjectClosureOrdering() {
doTest( doTest(
""" """
class Klass { class Klass {
fun Any.f(a: String, b: Int, c: Double, d: Any, e: Long) { fun Any.f(a: String, b: Int, c: Double, d: Any, e: Long) {
object : Runnable { object : Runnable {
override fun run() { override fun run() {
a + b + c + d + e + this@f + this@Klass a + b + c + d + e + this@f + this@Klass
} }
}.run() }.run()
}
} }
""", }
"\$f$1", """,
listOf("run()V", "<init>(LKlass;Ljava/lang/Object;Ljava/lang/String;IDLjava/lang/Object;J)V") "\$f$1",
listOf("run()V", "<init>(LKlass;Ljava/lang/Object;Ljava/lang/String;IDLjava/lang/Object;J)V")
) )
} }
fun testMemberAccessor() { fun testMemberAccessor() {
doTest( doTest(
""" """
class Outer(private val a: Int, private var b: String) { class Outer(private val a: Int, private var b: String) {
private fun c() { private fun c() {
} }
inner class Inner() { inner class Inner() {
init { init {
b = b + a b = b + a
c() c()
}
} }
} }
""", }
"Outer", """,
listOf( "Outer",
"c()V", listOf(
"<init>(ILjava/lang/String;)V", "c()V",
"access\$getB\$p(LOuter;)Ljava/lang/String;", "<init>(ILjava/lang/String;)V",
"access\$setB\$p(LOuter;Ljava/lang/String;)V", "access\$getB\$p(LOuter;)Ljava/lang/String;",
"access\$getA\$p(LOuter;)I", "access\$setB\$p(LOuter;Ljava/lang/String;)V",
"access\$c(LOuter;)V" "access\$getA\$p(LOuter;)I",
) "access\$c(LOuter;)V"
)
) )
} }
fun testDeterministicDefaultMethodImplOrder() { fun testDeterministicDefaultMethodImplOrder() {
doTest( doTest(
""" """
interface Base<K, V> { interface Base<K, V> {
fun getSize(): Int = 5 fun getSize(): Int = 5
fun size(): Int = getSize() fun size(): Int = getSize()
fun getKeys(): Int = 4 fun getKeys(): Int = 4
fun keySet() = getKeys() fun keySet() = getKeys()
fun getEntries(): Int = 3 fun getEntries(): Int = 3
fun entrySet() = getEntries() fun entrySet() = getEntries()
fun getValues(): Int = 2 fun getValues(): Int = 2
fun values() = getValues() fun values() = getValues()
fun removeEldestEntry(eldest: Any?): Boolean fun removeEldestEntry(eldest: Any?): Boolean
} }
class MinMap<K, V> : Base<K, V> { class MinMap<K, V> : Base<K, V> {
override fun removeEldestEntry(eldest: Any?) = true override fun removeEldestEntry(eldest: Any?) = true
} }
""", """,
"MinMap", "MinMap",
listOf("removeEldestEntry(Ljava/lang/Object;)Z", "<init>()V", "getSize()I", "size()I", "getKeys()I", "keySet()I", "getEntries()I", "entrySet()I", "getValues()I", "values()I") listOf(
"removeEldestEntry(Ljava/lang/Object;)Z",
"<init>()V",
"getSize()I",
"size()I",
"getKeys()I",
"keySet()I",
"getEntries()I",
"entrySet()I",
"getValues()I",
"values()I"
)
) )
} }
@@ -169,7 +184,13 @@ class MethodOrderTest: CodegenTestCase() {
val methodNames = ArrayList<String>() val methodNames = ArrayList<String>()
classReader.accept(object : ClassVisitor(Opcodes.API_VERSION) { classReader.accept(object : ClassVisitor(Opcodes.API_VERSION) {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? { override fun visitMethod(
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?
): MethodVisitor? {
methodNames.add(name + desc) methodNames.add(name + desc)
return null return null
} }
@@ -41,110 +41,110 @@ public class OuterClassGenTest extends CodegenTestCase {
return "outerClassInfo"; return "outerClassInfo";
} }
public void testClass() throws Exception { public void testClass() {
doTest("foo.Foo", "outerClassInfo"); doTest("foo.Foo", "outerClassInfo");
} }
public void testClassObject() throws Exception { public void testClassObject() {
doTest("foo.Foo$" + SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.asString(), "outerClassInfo"); doTest("foo.Foo$" + SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.asString(), "outerClassInfo");
} }
public void testInnerClass() throws Exception { public void testInnerClass() {
doTest("foo.Foo$InnerClass", "outerClassInfo"); doTest("foo.Foo$InnerClass", "outerClassInfo");
} }
public void testInnerObject() throws Exception { public void testInnerObject() {
doTest("foo.Foo$InnerObject", "outerClassInfo"); doTest("foo.Foo$InnerObject", "outerClassInfo");
} }
public void testLocalClassInFunction() throws Exception { public void testLocalClassInFunction() {
doTest("foo.Foo$foo$LocalClass", "foo.Foo$1LocalClass", "outerClassInfo"); doTest("foo.Foo$foo$LocalClass", "foo.Foo$1LocalClass", "outerClassInfo");
} }
public void testLocalObjectInFunction() throws Exception { public void testLocalObjectInFunction() {
doTest("foo.Foo$foo$LocalObject", "foo.Foo$1LocalObject", "outerClassInfo"); doTest("foo.Foo$foo$LocalObject", "foo.Foo$1LocalObject", "outerClassInfo");
} }
public void testObjectInPackageClass() throws Exception { public void testObjectInPackageClass() {
doTest("foo.PackageInnerObject", "outerClassInfo"); doTest("foo.PackageInnerObject", "outerClassInfo");
} }
public void testLambdaInNoInlineFun() throws Exception { public void testLambdaInNoInlineFun() {
doTest("foo.Foo$foo$1", "foo.Foo$1Lambda", "outerClassInfo"); doTest("foo.Foo$foo$1", "foo.Foo$1Lambda", "outerClassInfo");
} }
public void testLambdaInConstructor() throws Exception { public void testLambdaInConstructor() {
doTest("foo.Foo$s$1", "foo.Foo$1LambdaInConstructor", "outerClassInfo"); doTest("foo.Foo$s$1", "foo.Foo$1LambdaInConstructor", "outerClassInfo");
} }
public void testObjectLiteralInPackageClass() throws Exception { public void testObjectLiteralInPackageClass() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/OuterClassInfo", null, null); OuterClassInfo expectedInfo = new OuterClassInfo("foo/OuterClassInfo", null, null);
doCustomTest("foo/OuterClassInfoKt\\$packageObjectLiteral\\$1", expectedInfo, "outerClassInfo"); doCustomTest("foo/OuterClassInfoKt\\$packageObjectLiteral\\$1", expectedInfo, "outerClassInfo");
} }
public void testLocalClassInTopLevelFunction() throws Exception { public void testLocalClassInTopLevelFunction() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/OuterClassInfo", "packageMethod", "(Lfoo/Foo;)V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/OuterClassInfo", "packageMethod", "(Lfoo/Foo;)V");
doCustomTest("foo/OuterClassInfoKt\\$packageMethod\\$PackageLocalClass", expectedInfo, "outerClassInfo"); doCustomTest("foo/OuterClassInfoKt\\$packageMethod\\$PackageLocalClass", expectedInfo, "outerClassInfo");
} }
public void testLocalObjectInTopLevelFunction() throws Exception { public void testLocalObjectInTopLevelFunction() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/OuterClassInfo", "packageMethod", "(Lfoo/Foo;)V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/OuterClassInfo", "packageMethod", "(Lfoo/Foo;)V");
doCustomTest("foo/OuterClassInfoKt\\$packageMethod\\$PackageLocalObject", expectedInfo, "outerClassInfo"); doCustomTest("foo/OuterClassInfoKt\\$packageMethod\\$PackageLocalObject", expectedInfo, "outerClassInfo");
} }
public void testLocalObjectInInlineFunction() throws Exception { public void testLocalObjectInInlineFunction() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/Foo", "inlineFoo", "(Lkotlin/jvm/functions/Function0;)V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/Foo", "inlineFoo", "(Lkotlin/jvm/functions/Function0;)V");
doCustomTest("foo/Foo\\$inlineFoo\\$localObject\\$1", expectedInfo, "inlineObject"); doCustomTest("foo/Foo\\$inlineFoo\\$localObject\\$1", expectedInfo, "inlineObject");
} }
public void testLocalObjectInlined() throws Exception { public void testLocalObjectInlined() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "callToInline", "()V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "callToInline", "()V");
doCustomTest("foo/Bar\\$callToInline\\$\\$inlined\\$inlineFoo\\$1", expectedInfo, "inlineObject"); doCustomTest("foo/Bar\\$callToInline\\$\\$inlined\\$inlineFoo\\$1", expectedInfo, "inlineObject");
} }
public void testLocalObjectInInlineLambda() throws Exception { public void testLocalObjectInInlineLambda() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "objectInInlineLambda", "()V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "objectInInlineLambda", "()V");
doCustomTest("foo/Bar\\$objectInInlineLambda\\$\\$inlined\\$simpleFoo\\$lambda\\$1", expectedInfo, "inlineObject"); doCustomTest("foo/Bar\\$objectInInlineLambda\\$\\$inlined\\$simpleFoo\\$lambda\\$1", expectedInfo, "inlineObject");
} }
public void testLocalObjectInLambdaInlinedIntoObject() throws Exception { public void testLocalObjectInLambdaInlinedIntoObject() {
OuterClassInfo intoObjectInfo = new OuterClassInfo("foo/Bar", "objectInLambdaInlinedIntoObject", "()V"); OuterClassInfo intoObjectInfo = new OuterClassInfo("foo/Bar", "objectInLambdaInlinedIntoObject", "()V");
doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1", intoObjectInfo, "inlineObject"); doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1", intoObjectInfo, "inlineObject");
} }
public void testLocalObjectInLambdaInlinedIntoObject2() throws Exception { public void testLocalObjectInLambdaInlinedIntoObject2() {
OuterClassInfo objectInLambda = new OuterClassInfo("foo/Bar$objectInLambdaInlinedIntoObject$$inlined$inlineFoo$1", "run", "()V"); OuterClassInfo objectInLambda = new OuterClassInfo("foo/Bar$objectInLambdaInlinedIntoObject$$inlined$inlineFoo$1", "run", "()V");
doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1\\$lambda\\$1", doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1\\$lambda\\$1",
objectInLambda, "inlineObject"); objectInLambda, "inlineObject");
} }
public void testLambdaInInlineFunction() throws Exception { public void testLambdaInInlineFunction() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/Foo", "inlineFoo", "(Lkotlin/jvm/functions/Function0;)V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/Foo", "inlineFoo", "(Lkotlin/jvm/functions/Function0;)V");
doCustomTest("foo/Foo\\$inlineFoo\\$1", expectedInfo, "inlineLambda"); doCustomTest("foo/Foo\\$inlineFoo\\$1", expectedInfo, "inlineLambda");
} }
public void testLambdaInlined() throws Exception { public void testLambdaInlined() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "callToInline", "()V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "callToInline", "()V");
doCustomTest("foo/Bar\\$callToInline\\$\\$inlined\\$inlineFoo\\$1", expectedInfo, "inlineLambda"); doCustomTest("foo/Bar\\$callToInline\\$\\$inlined\\$inlineFoo\\$1", expectedInfo, "inlineLambda");
} }
public void testLambdaInInlineLambda() throws Exception { public void testLambdaInInlineLambda() {
OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "objectInInlineLambda", "()V"); OuterClassInfo expectedInfo = new OuterClassInfo("foo/Bar", "objectInInlineLambda", "()V");
doCustomTest("foo/Bar\\$objectInInlineLambda\\$\\$inlined\\$simpleFoo\\$lambda\\$1", expectedInfo, "inlineLambda"); doCustomTest("foo/Bar\\$objectInInlineLambda\\$\\$inlined\\$simpleFoo\\$lambda\\$1", expectedInfo, "inlineLambda");
} }
public void testLambdaInLambdaInlinedIntoObject() throws Exception { public void testLambdaInLambdaInlinedIntoObject() {
OuterClassInfo intoObjectInfo = new OuterClassInfo("foo/Bar", "objectInLambdaInlinedIntoObject", "()V"); OuterClassInfo intoObjectInfo = new OuterClassInfo("foo/Bar", "objectInLambdaInlinedIntoObject", "()V");
doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1", intoObjectInfo, "inlineLambda"); doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1", intoObjectInfo, "inlineLambda");
} }
public void testLambdaInLambdaInlinedIntoObject2() throws Exception { public void testLambdaInLambdaInlinedIntoObject2() {
OuterClassInfo objectInLambda = new OuterClassInfo("foo/Bar$objectInLambdaInlinedIntoObject$$inlined$inlineFoo$1", "invoke", "()V"); OuterClassInfo objectInLambda = new OuterClassInfo("foo/Bar$objectInLambdaInlinedIntoObject$$inlined$inlineFoo$1", "invoke", "()V");
doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1\\$lambda\\$1", doCustomTest("foo/Bar\\$objectInLambdaInlinedIntoObject\\$\\$inlined\\$inlineFoo\\$1\\$lambda\\$1",
objectInLambda, "inlineLambda"); objectInLambda, "inlineLambda");
} }
private void doTest(@NotNull String classFqName, @NotNull String testDataFile) throws Exception { private void doTest(@NotNull String classFqName, @NotNull String testDataFile) {
doTest(classFqName, classFqName, testDataFile); doTest(classFqName, classFqName, testDataFile);
} }
@@ -154,7 +154,7 @@ public class OuterClassGenTest extends CodegenTestCase {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
} }
private void doTest(@NotNull String classFqName, @NotNull String javaClassName, @NotNull String testDataFile) throws Exception { private void doTest(@NotNull String classFqName, @NotNull String javaClassName, @NotNull String testDataFile) {
File javaOut = CodegenTestUtil.compileJava( File javaOut = CodegenTestUtil.compileJava(
Collections.singletonList(KotlinTestUtils.getTestDataPathBase() + "/codegen/" + getPrefix() + "/" + testDataFile + ".java"), Collections.singletonList(KotlinTestUtils.getTestDataPathBase() + "/codegen/" + getPrefix() + "/" + testDataFile + ".java"),
Collections.emptyList(), Collections.emptyList(),
@@ -176,14 +176,10 @@ public class OuterClassGenTest extends CodegenTestCase {
) { ) {
ClassReader kotlinReader = getKotlinClassReader(internalNameRegexp, testDataFile); ClassReader kotlinReader = getKotlinClassReader(internalNameRegexp, testDataFile);
OuterClassInfo kotlinInfo = readOuterClassInfo(kotlinReader); OuterClassInfo kotlinInfo = readOuterClassInfo(kotlinReader);
assertNotNull(kotlinInfo);
String message = "Error in enclosingMethodInfo info for class: " + kotlinReader.getClassName(); String message = "Error in enclosingMethodInfo info for class: " + kotlinReader.getClassName();
if (kotlinInfo == null) { assertTrue(message + "\n" + kotlinInfo.getOwner() + " doesn't start with " + expectedInfo.getOwner(),
assertNull(expectedInfo.getOwner()); kotlinInfo.getOwner().startsWith(expectedInfo.getOwner()));
}
else {
assertTrue(message + "\n" + kotlinInfo.getOwner() + " doesn't start with " + expectedInfo.getOwner(),
kotlinInfo.getOwner().startsWith(expectedInfo.getOwner()));
}
assertEquals(message, expectedInfo.getMethodName(), kotlinInfo.getMethodName()); assertEquals(message, expectedInfo.getMethodName(), kotlinInfo.getMethodName());
assertEquals(message, expectedInfo.getMethodDesc(), kotlinInfo.getMethodDesc()); assertEquals(message, expectedInfo.getMethodDesc(), kotlinInfo.getMethodDesc());
} }
@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
data class OuterClassInfo( data class OuterClassInfo(
val owner: String, val owner: String,
val methodName: String?, val methodName: String?,
val methodDesc: String? val methodDesc: String?
) )
@@ -171,6 +171,7 @@ public class PackageGenTest extends CodegenTestCase {
assertEquals("beer", result.toString()); assertEquals("beer", result.toString());
} }
@SuppressWarnings("StringOperationCanBeSimplified")
public void testJavaEquals() throws Exception { public void testJavaEquals() throws Exception {
loadText("fun foo(s1: String, s2: String) = s1 == s2"); loadText("fun foo(s1: String, s2: String) = s1 == s2");
Method main = generateFunction(); Method main = generateFunction();
@@ -178,6 +179,7 @@ public class PackageGenTest extends CodegenTestCase {
assertEquals(Boolean.FALSE, main.invoke(null, new String("kotlin"), new String("ceylon"))); assertEquals(Boolean.FALSE, main.invoke(null, new String("kotlin"), new String("ceylon")));
} }
@SuppressWarnings("StringOperationCanBeSimplified")
public void testJavaNotEquals() throws Exception { public void testJavaNotEquals() throws Exception {
loadText("fun foo(s1: String, s2: String) = s1 != s2"); loadText("fun foo(s1: String, s2: String) = s1 != s2");
Method main = generateFunction(); Method main = generateFunction();
@@ -200,6 +202,7 @@ public class PackageGenTest extends CodegenTestCase {
assertEquals(Boolean.FALSE, main.invoke(null, "kotlin")); assertEquals(Boolean.FALSE, main.invoke(null, "kotlin"));
} }
@SuppressWarnings("StringOperationCanBeSimplified")
public void testTripleEq() throws Exception { public void testTripleEq() throws Exception {
loadText("fun foo(s1: String?, s2: String?) = s1 === s2"); loadText("fun foo(s1: String?, s2: String?) = s1 === s2");
Method main = generateFunction(); Method main = generateFunction();
@@ -209,6 +212,7 @@ public class PackageGenTest extends CodegenTestCase {
assertEquals(Boolean.FALSE, main.invoke(null, s1, s2)); assertEquals(Boolean.FALSE, main.invoke(null, s1, s2));
} }
@SuppressWarnings("StringOperationCanBeSimplified")
public void testTripleNotEq() throws Exception { public void testTripleNotEq() throws Exception {
loadText("fun foo(s1: String?, s2: String?) = s1 !== s2"); loadText("fun foo(s1: String?, s2: String?) = s1 !== s2");
Method main = generateFunction(); Method main = generateFunction();
@@ -301,7 +305,7 @@ public class PackageGenTest extends CodegenTestCase {
assertEquals(610, c.gridx); assertEquals(610, c.gridx);
} }
public void testIncrementAsLastOperation() throws Exception { public void testIncrementAsLastOperation() {
loadText("fun foo() { var a = 0; a++; }"); loadText("fun foo() { var a = 0; a++; }");
generateFunction(); // make sure we're not falling off end of code generateFunction(); // make sure we're not falling off end of code
} }
@@ -440,7 +444,7 @@ public class PackageGenTest extends CodegenTestCase {
public void testExplicitCallOfBooleanNotIntrinsic() throws Exception { public void testExplicitCallOfBooleanNotIntrinsic() throws Exception {
loadText("fun foo(a: Boolean) = a.not()"); loadText("fun foo(a: Boolean) = a.not()");
Method main = generateFunction(); Method main = generateFunction();
assertEquals(false, ((Boolean) main.invoke(null, true)).booleanValue()); assertFalse(((Boolean) main.invoke(null, true)).booleanValue());
} }
public void testAppendArrayToString() throws Exception { public void testAppendArrayToString() throws Exception {
@@ -89,22 +89,22 @@ public class PrimitiveTypesTest extends CodegenTestCase {
public void testShort() throws Exception { public void testShort() throws Exception {
binOpTest("fun foo(a: Short, b: Short): Int = a + b", binOpTest("fun foo(a: Short, b: Short): Int = a + b",
Short.valueOf((short) 32767), Short.valueOf((short) 32767), 65534); Short.valueOf((short) 32767), Short.valueOf((short) 32767), 65534);
} }
public void testShortCmp() throws Exception { public void testShortCmp() throws Exception {
binOpTest("fun foo(a: Short, b: Short): Boolean = a == b", binOpTest("fun foo(a: Short, b: Short): Boolean = a == b",
Short.valueOf((short) 32767), Short.valueOf((short) 32767), true); Short.valueOf((short) 32767), Short.valueOf((short) 32767), true);
} }
public void testByte() throws Exception { public void testByte() throws Exception {
binOpTest("fun foo(a: Byte, b: Byte): Int = a + b", binOpTest("fun foo(a: Byte, b: Byte): Int = a + b",
Byte.valueOf((byte) 127), Byte.valueOf((byte) 127), 254); Byte.valueOf((byte) 127), Byte.valueOf((byte) 127), 254);
} }
public void testByteCmp() throws Exception { public void testByteCmp() throws Exception {
binOpTest("fun foo(a: Byte, b: Byte): Int = if (a == b) 1 else 0", binOpTest("fun foo(a: Byte, b: Byte): Int = if (a == b) 1 else 0",
Byte.valueOf((byte) 127), Byte.valueOf((byte) 127), 1); Byte.valueOf((byte) 127), Byte.valueOf((byte) 127), 1);
} }
public void testByteLess() throws Exception { public void testByteLess() throws Exception {
@@ -39,18 +39,18 @@ class ReflectionClassLoaderTest : CodegenTestCase() {
} }
fun testSimpleDifferentClassLoaders() { fun testSimpleDifferentClassLoaders() {
loadFile(prefix + "/differentClassLoaders.kt") loadFile("$prefix/differentClassLoaders.kt")
doTest( doTest(
createClassLoader(), createClassLoader(),
createClassLoader() createClassLoader()
) )
} }
fun testClassLoaderWithNonTrivialEqualsAndHashCode() { fun testClassLoaderWithNonTrivialEqualsAndHashCode() {
// Check that class loaders do not participate as keys in hash maps (use identity hash maps instead) // Check that class loaders do not participate as keys in hash maps (use identity hash maps instead)
loadFile(prefix + "/differentClassLoaders.kt") loadFile("$prefix/differentClassLoaders.kt")
class BrokenEqualsClassLoader(parent: ClassLoader) : ClassLoader(parent) { class BrokenEqualsClassLoader(parent: ClassLoader) : ClassLoader(parent) {
override fun equals(other: Any?) = true override fun equals(other: Any?) = true
@@ -58,23 +58,23 @@ class ReflectionClassLoaderTest : CodegenTestCase() {
} }
doTest( doTest(
BrokenEqualsClassLoader(createClassLoader()), BrokenEqualsClassLoader(createClassLoader()),
BrokenEqualsClassLoader(createClassLoader()) BrokenEqualsClassLoader(createClassLoader())
) )
} }
fun testParentFirst() { fun testParentFirst() {
// Check that for a child class loader, a class reference would be the same as for his parent // Check that for a child class loader, a class reference would be the same as for his parent
loadFile(prefix + "/parentFirst.kt") loadFile("$prefix/parentFirst.kt")
class ChildClassLoader(parent: ClassLoader) : ClassLoader(parent) class ChildClassLoader(parent: ClassLoader) : ClassLoader(parent)
val parent = createClassLoader() val parent = createClassLoader()
doTest( doTest(
parent, parent,
ChildClassLoader(parent) ChildClassLoader(parent)
) )
} }
} }
@@ -46,16 +46,16 @@ class ScriptGenTest : CodegenTestCase() {
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
additionalDependencies = additionalDependencies =
System.getenv("PROJECT_CLASSES_DIRS")?.split(File.pathSeparator)?.map { File(it) } System.getenv("PROJECT_CLASSES_DIRS")?.split(File.pathSeparator)?.map { File(it) }
?: listOf( ?: listOf(
"compiler/build/classes/kotlin/test", "compiler/build/classes/kotlin/test",
"build/compiler/classes/kotlin/test", "build/compiler/classes/kotlin/test",
"out/test/compiler.test", "out/test/compiler.test",
"out/test/compiler_test" "out/test/compiler_test"
) )
.mapNotNull { File(it).canonicalFile.takeIf { it.isDirectory } } .mapNotNull { File(it).canonicalFile.takeIf(File::isDirectory) }
.takeIf { it.isNotEmpty() } .takeIf { it.isNotEmpty() }
?: throw IllegalStateException("Unable to get classes output dirs, set PROJECT_CLASSES_DIRS environment variable") ?: throw IllegalStateException("Unable to get classes output dirs, set PROJECT_CLASSES_DIRS environment variable")
} }
fun testLanguage() { fun testLanguage() {
@@ -136,7 +136,9 @@ class ScriptGenTest : CodegenTestCase() {
} }
} }
@Suppress("unused")
@ScriptTemplateDefinition( @ScriptTemplateDefinition(
scriptFilePattern =".*\\.lang\\.kts", scriptFilePattern = ".*\\.lang\\.kts",
resolver = TestKotlinScriptDependenciesResolver::class) resolver = TestKotlinScriptDependenciesResolver::class
)
abstract class ScriptWithIntParam(val num: Int) abstract class ScriptWithIntParam(val num: Int)
@@ -25,6 +25,7 @@ import org.jetbrains.org.objectweb.asm.Opcodes;
public class SourceInfoGenTest extends CodegenTestCase { public class SourceInfoGenTest extends CodegenTestCase {
private static final String TEST_FOLDER = "sourceInfo/"; private static final String TEST_FOLDER = "sourceInfo/";
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
@@ -50,7 +51,6 @@ public class SourceInfoGenTest extends CodegenTestCase {
public void visitSource(String source, String debug) { public void visitSource(String source, String debug) {
producer[0] = source; producer[0] = source;
} }
}, 0); }, 0);
return producer[0]; return producer[0];
} }
@@ -23,11 +23,13 @@ import java.io.FileInputStream
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
class TestStdlibWithDxTest { class TestStdlibWithDxTest {
@Test fun testRuntimeWithDx() { @Test
fun testRuntimeWithDx() {
doTest(ForTestCompileRuntime.runtimeJarForTests()) doTest(ForTestCompileRuntime.runtimeJarForTests())
} }
@Test fun testReflectWithDx() { @Test
fun testReflectWithDx() {
doTest(ForTestCompileRuntime.reflectJarForTests()) doTest(ForTestCompileRuntime.reflectJarForTests())
} }
@@ -34,56 +34,56 @@ public class VarArgTest extends CodegenTestCase {
loadText("fun test(vararg ts: String) = ts"); loadText("fun test(vararg ts: String) = ts");
Method main = generateFunction(); Method main = generateFunction();
String[] args = {"mama", "papa"}; String[] args = {"mama", "papa"};
assertTrue(args == main.invoke(null, new Object[]{ args } )); assertSame(args, main.invoke(null, new Object[] {args}));
} }
public void testIntArray() throws InvocationTargetException, IllegalAccessException { public void testIntArray() throws InvocationTargetException, IllegalAccessException {
loadText("fun test(vararg ts: Int) = ts"); loadText("fun test(vararg ts: Int) = ts");
Method main = generateFunction(); Method main = generateFunction();
int[] args = {3, 4}; int[] args = {3, 4};
assertTrue(args == main.invoke(null, new Object[]{ args })); assertSame(args, main.invoke(null, new Object[] {args}));
} }
public void testIntArrayKotlinNoArgs() throws InvocationTargetException, IllegalAccessException { public void testIntArrayKotlinNoArgs() throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(); fun testf(vararg ts: Int) = ts"); loadText("fun test() = testf(); fun testf(vararg ts: Int) = ts");
Method main = generateFunction("test"); Method main = generateFunction("test");
Object res = main.invoke(null); Object res = main.invoke(null);
assertTrue(((int[])res).length == 0); assertEquals(0, ((int[]) res).length);
} }
public void testIntArrayKotlin() throws InvocationTargetException, IllegalAccessException { public void testIntArrayKotlin() throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(239, 7); fun testf(vararg ts: Int) = ts"); loadText("fun test() = testf(239, 7); fun testf(vararg ts: Int) = ts");
Method main = generateFunction("test"); Method main = generateFunction("test");
Object res = main.invoke(null); Object res = main.invoke(null);
assertTrue(((int[])res).length == 2); assertEquals(2, ((int[]) res).length);
assertTrue(((int[])res)[0] == 239); assertEquals(239, ((int[]) res)[0]);
assertTrue(((int[])res)[1] == 7); assertEquals(7, ((int[]) res)[1]);
} }
public void testNullableIntArrayKotlin() throws InvocationTargetException, IllegalAccessException { public void testNullableIntArrayKotlin() throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(239.toByte(), 7.toByte()); fun testf(vararg ts: Byte?) = ts"); loadText("fun test() = testf(239.toByte(), 7.toByte()); fun testf(vararg ts: Byte?) = ts");
Method main = generateFunction("test"); Method main = generateFunction("test");
Object res = main.invoke(null); Object res = main.invoke(null);
assertTrue(((Byte[])res).length == 2); assertEquals(2, ((Byte[]) res).length);
assertTrue(((Byte[])res)[0] == (byte)239); assertEquals((byte) ((Byte[]) res)[0], (byte) 239);
assertTrue(((Byte[])res)[1] == 7); assertEquals(7, (byte) ((Byte[]) res)[1]);
} }
public void testIntArrayKotlinObj() throws InvocationTargetException, IllegalAccessException { public void testIntArrayKotlinObj() throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = testf(\"239\"); fun testf(vararg ts: String) = ts"); loadText("fun test() = testf(\"239\"); fun testf(vararg ts: String) = ts");
Method main = generateFunction("test"); Method main = generateFunction("test");
Object res = main.invoke(null); Object res = main.invoke(null);
assertTrue(((String[])res).length == 1); assertEquals(1, ((String[]) res).length);
assertTrue(((String[])res)[0].equals("239")); assertEquals("239", ((String[]) res)[0]);
} }
public void testArrayT() throws InvocationTargetException, IllegalAccessException { public void testArrayT() throws InvocationTargetException, IllegalAccessException {
loadText("fun test() = _array(2, 4); fun <T> _array(vararg elements : T) = elements"); loadText("fun test() = _array(2, 4); fun <T> _array(vararg elements : T) = elements");
Method main = generateFunction("test"); Method main = generateFunction("test");
Object res = main.invoke(null); Object res = main.invoke(null);
assertTrue(((Integer[])res).length == 2); assertEquals(2, ((Integer[]) res).length);
assertTrue(((Integer[])res)[0].equals(2)); assertEquals(2, (int) ((Integer[]) res)[0]);
assertTrue(((Integer[])res)[1].equals(4)); assertEquals(4, (int) ((Integer[]) res)[1]);
} }
public void testArrayAsVararg() throws InvocationTargetException, IllegalAccessException { public void testArrayAsVararg() throws InvocationTargetException, IllegalAccessException {
@@ -91,7 +91,7 @@ public class VarArgTest extends CodegenTestCase {
Method main = generateFunction("test"); Method main = generateFunction("test");
String[] args = {"mama", "papa"}; String[] args = {"mama", "papa"};
String[] result = (String []) main.invoke(null, new Object[] {args}); String[] result = (String []) main.invoke(null, new Object[] {args});
assertTrue(args != result); assertNotSame(args, result);
assertTrue(Arrays.equals(args, result)); assertTrue(Arrays.equals(args, result));
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.android.parcel package org.jetbrains.kotlin.android.parcel
@@ -37,11 +26,11 @@ import java.util.concurrent.TimeUnit
abstract class AbstractParcelBoxTest : CodegenTestCase() { abstract class AbstractParcelBoxTest : CodegenTestCase() {
protected companion object { protected companion object {
val BASE_DIR = "plugins/android-extensions/android-extensions-compiler/testData/parcel/box" const val BASE_DIR = "plugins/android-extensions/android-extensions-compiler/testData/parcel/box"
val LIBRARY_KT = File(File(BASE_DIR).parentFile, "boxLib.kt") val LIBRARY_KT = File(File(BASE_DIR).parentFile, "boxLib.kt")
private val JUNIT_GENERATED_TEST_CLASS_BYTES by lazy { constructSyntheticTestClass() } private val JUNIT_GENERATED_TEST_CLASS_BYTES by lazy { constructSyntheticTestClass() }
private val JUNIT_GENERATED_TEST_CLASS_FQNAME = "test.JunitTest" private const val JUNIT_GENERATED_TEST_CLASS_FQNAME = "test.JunitTest"
private fun constructSyntheticTestClass(): ByteArray { private fun constructSyntheticTestClass(): ByteArray {
return with(ClassWriter(COMPUTE_MAXS or COMPUTE_FRAMES)) { return with(ClassWriter(COMPUTE_MAXS or COMPUTE_FRAMES)) {
@@ -104,12 +93,12 @@ abstract class AbstractParcelBoxTest : CodegenTestCase() {
} }
override fun doTest(filePath: String) { override fun doTest(filePath: String) {
super.doTest(File(BASE_DIR, filePath + ".kt").absolutePath) super.doTest(File(BASE_DIR, "$filePath.kt").absolutePath)
} }
private val androidPluginPath: String by lazy { private val androidPluginPath: String by lazy {
System.getProperty("ideaSdk.androidPlugin.path")?.takeIf { File(it).isDirectory } System.getProperty("ideaSdk.androidPlugin.path")?.takeIf { File(it).isDirectory }
?: throw RuntimeException("Unable to get a valid path from 'ideaSdk.androidPlugin.path' property, please point it to the Idea android plugin location") ?: throw RuntimeException("Unable to get a valid path from 'ideaSdk.androidPlugin.path' property, please point it to the Idea android plugin location")
} }
private fun getClasspathForTest(): List<File> { private fun getClasspathForTest(): List<File> {
@@ -117,10 +106,10 @@ abstract class AbstractParcelBoxTest : CodegenTestCase() {
val layoutLibJars = listOf(File(androidPluginPath, "layoutlib.jar"), File(androidPluginPath, "layoutlib-api.jar")) val layoutLibJars = listOf(File(androidPluginPath, "layoutlib.jar"), File(androidPluginPath, "layoutlib-api.jar"))
val robolectricClasspath = System.getProperty("robolectric.classpath") val robolectricClasspath = System.getProperty("robolectric.classpath")
?: throw RuntimeException("Unable to get a valid classpath from 'robolectric.classpath' property, please set it accordingly") ?: throw RuntimeException("Unable to get a valid classpath from 'robolectric.classpath' property, please set it accordingly")
val robolectricJars = robolectricClasspath.split(File.pathSeparator) val robolectricJars = robolectricClasspath.split(File.pathSeparator)
.map { File(it) } .map { File(it) }
.sortedBy { it.nameWithoutExtension } .sortedBy { it.nameWithoutExtension }
val junitCoreResourceName = JUnitCore::class.java.name.replace('.', '/') + ".class" val junitCoreResourceName = JUnitCore::class.java.name.replace('.', '/') + ".class"
val junitJar = File(JUnitCore::class.java.classLoader.getResource(junitCoreResourceName).file.substringBeforeLast('!')) val junitJar = File(JUnitCore::class.java.classLoader.getResource(junitCoreResourceName).file.substringBeforeLast('!'))
@@ -151,12 +140,12 @@ abstract class AbstractParcelBoxTest : CodegenTestCase() {
classFileFactory.getClassFiles().forEach { writeClass(it.relativePath, it.asByteArray()) } classFileFactory.getClassFiles().forEach { writeClass(it.relativePath, it.asByteArray()) }
val process = ProcessBuilder( val process = ProcessBuilder(
javaExe.absolutePath, javaExe.absolutePath,
"-ea", "-ea",
"-classpath", "-classpath",
(libraryClasspath + dirForTestClasses).joinToString(File.pathSeparator), (libraryClasspath + dirForTestClasses).joinToString(File.pathSeparator),
JUnitCore::class.java.name, JUnitCore::class.java.name,
JUNIT_GENERATED_TEST_CLASS_FQNAME JUNIT_GENERATED_TEST_CLASS_FQNAME
).inheritIO().start() ).inheritIO().start()
process.waitFor(3, TimeUnit.MINUTES) process.waitFor(3, TimeUnit.MINUTES)
@@ -175,4 +164,4 @@ abstract class AbstractParcelBoxTest : CodegenTestCase() {
addAndroidExtensionsRuntimeLibrary(environment) addAndroidExtensionsRuntimeLibrary(environment)
environment.updateClasspath(listOf(JvmClasspathRoot(File(androidPluginPath, "layoutlib.jar")))) environment.updateClasspath(listOf(JvmClasspathRoot(File(androidPluginPath, "layoutlib.jar"))))
} }
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.android.parcel package org.jetbrains.kotlin.android.parcel
@@ -28,7 +17,9 @@ abstract class AbstractParcelBytecodeListingTest : AbstractAsmLikeInstructionLis
AndroidComponentRegistrar.registerParcelExtensions(environment.project) AndroidComponentRegistrar.registerParcelExtensions(environment.project)
addAndroidExtensionsRuntimeLibrary(environment) addAndroidExtensionsRuntimeLibrary(environment)
val androidPluginPath = System.getProperty("ideaSdk.androidPlugin.path")?.takeIf { File(it).isDirectory } val androidPluginPath = System.getProperty("ideaSdk.androidPlugin.path")?.takeIf { File(it).isDirectory }
?: throw RuntimeException("Unable to get a valid path from 'ideaSdk.androidPlugin.path' property, please point it to the Idea android plugin location") ?: throw RuntimeException(
"Unable to get a valid path from 'ideaSdk.androidPlugin.path' property, please point it to the Idea android plugin location"
)
environment.updateClasspath(listOf(JvmClasspathRoot(File(androidPluginPath, "layoutlib.jar")))) environment.updateClasspath(listOf(JvmClasspathRoot(File(androidPluginPath, "layoutlib.jar"))))
} }
} }
@@ -1,24 +1,12 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.android.synthetic.test package org.jetbrains.kotlin.android.synthetic.test
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import com.intellij.util.Processor
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.codegen.CodegenTestFiles import org.jetbrains.kotlin.codegen.CodegenTestFiles
@@ -28,7 +16,6 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File import java.io.File
import java.net.URL import java.net.URL
import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
abstract class AbstractAndroidBoxTest : AbstractBlackBoxCodegenTest() { abstract class AbstractAndroidBoxTest : AbstractBlackBoxCodegenTest() {
@@ -42,7 +29,9 @@ abstract class AbstractAndroidBoxTest : AbstractBlackBoxCodegenTest() {
} }
private fun createEnvironmentForConfiguration(configuration: CompilerConfiguration, path: String) { private fun createEnvironmentForConfiguration(configuration: CompilerConfiguration, path: String) {
val layoutPaths = File(path).listFiles { it -> it.name.startsWith("layout") && it.isDirectory }!!.map { "$path${it.name}/" } val layoutPaths = File(path)
.listFiles { file -> file.name.startsWith("layout") && file.isDirectory }!!
.map { "$path${it.name}/" }
myEnvironment = createTestEnvironment(configuration, layoutPaths) myEnvironment = createTestEnvironment(configuration, layoutPaths)
} }
@@ -63,11 +52,12 @@ abstract class AbstractAndroidBoxTest : AbstractBlackBoxCodegenTest() {
} }
private fun getFakeFiles(path: String): Collection<String> { private fun getFakeFiles(path: String): Collection<String> {
return FileUtil.findFilesByMask(Pattern.compile("^Fake.*\\.kt$"), File(path.replace(getTestName(true), ""))).map { relativePath(it) } return FileUtil.findFilesByMask(Pattern.compile("^Fake.*\\.kt$"), File(path.replace(getTestName(true), "")))
.map { relativePath(it) }
} }
private fun needsInvocationTest(path: String): Boolean { private fun needsInvocationTest(path: String): Boolean {
return !FileUtil.findFilesByMask(Pattern.compile("^0.kt$"), File(path)).isEmpty() return FileUtil.findFilesByMask(Pattern.compile("^0.kt$"), File(path)).isNotEmpty()
} }
override fun codegenTestBasePath(): String { override fun codegenTestBasePath(): String {
@@ -76,35 +66,33 @@ abstract class AbstractAndroidBoxTest : AbstractBlackBoxCodegenTest() {
private fun doMultiFileTest(path: String, additionalFiles: Collection<String>? = null) { private fun doMultiFileTest(path: String, additionalFiles: Collection<String>? = null) {
val files = mutableListOf<String>() val files = mutableListOf<String>()
FileUtil.processFilesRecursively(File(path), object : Processor<File> { FileUtil.processFilesRecursively(File(path)) { file ->
override fun process(file: File?): Boolean { when (file!!.name) {
when (file!!.name) { "1.kt" -> {
"1.kt" -> { if (additionalFiles == null) files.add(relativePath(file))
if (additionalFiles == null) files.add(relativePath(file)) }
} "0.kt" -> {
"0.kt" -> { if (additionalFiles != null) files.add(relativePath(file))
if (additionalFiles != null) files.add(relativePath(file)) }
} else -> {
else -> { if (file.name.endsWith(".kt")) files.add(relativePath(file))
if (file.name.endsWith(".kt")) files.add(relativePath(file))
}
} }
return true
} }
}) true
}
for (file in File("plugins/android-extensions/android-extensions-runtime/src").walk()) { for (file in File("plugins/android-extensions/android-extensions-runtime/src").walk()) {
if (file.extension == "kt") files += relativePath(file.absoluteFile) if (file.extension == "kt") files += relativePath(file.absoluteFile)
} }
Collections.sort(files) files.sort()
if (additionalFiles != null) { if (additionalFiles != null) {
files.addAll(additionalFiles) files.addAll(additionalFiles)
} }
myFiles = CodegenTestFiles.create( myFiles = CodegenTestFiles.create(
myEnvironment!!.project, myEnvironment!!.project,
ArrayUtil.toStringArray(files), ArrayUtil.toStringArray(files),
KotlinTestUtils.getHomeDirectory() + "/plugins/android-extensions/android-extensions-compiler/testData" KotlinTestUtils.getHomeDirectory() + "/plugins/android-extensions/android-extensions-compiler/testData"
) )
blackBox(true) blackBox(true)
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.android.synthetic.test package org.jetbrains.kotlin.android.synthetic.test
@@ -41,20 +30,20 @@ abstract class AbstractAndroidSyntheticPropertyDescriptorTest : KtUsefulTestCase
val analysisResult = JvmResolveUtil.analyzeAndCheckForErrors(listOf(), env) val analysisResult = JvmResolveUtil.analyzeAndCheckForErrors(listOf(), env)
val fragmentProvider = val fragmentProvider =
ext.getPackageFragmentProvider( ext.getPackageFragmentProvider(
project, analysisResult.moduleDescriptor, LockBasedStorageManager.NO_LOCKS, project, analysisResult.moduleDescriptor, LockBasedStorageManager.NO_LOCKS,
KotlinTestUtils.DUMMY_EXCEPTION_ON_ERROR_TRACE, null, LookupTracker.DO_NOTHING KotlinTestUtils.DUMMY_EXCEPTION_ON_ERROR_TRACE, null, LookupTracker.DO_NOTHING
) as AndroidSyntheticPackageFragmentProvider ) as AndroidSyntheticPackageFragmentProvider
val renderer = DescriptorRenderer.COMPACT_WITH_MODIFIERS val renderer = DescriptorRenderer.COMPACT_WITH_MODIFIERS
val expected = fragmentProvider.packages.values val expected = fragmentProvider.packages.values
.map { it() } .map { it() }
.sortedBy { it.fqName.asString() } .sortedBy { it.fqName.asString() }
.joinToString(separator = "\n\n\n") { .joinToString(separator = "\n\n\n") { packageFragment ->
val descriptors = it.getMemberScope().getContributedDescriptors() val descriptors = packageFragment.getMemberScope().getContributedDescriptors()
.sortedWith(MemberComparator.INSTANCE) .sortedWith(MemberComparator.INSTANCE)
.map { " " + renderer.render(it) }.joinToString("\n") .joinToString("\n") { " " + renderer.render(it) }
it.fqName.asString() + (if (descriptors.isNotEmpty()) "\n\n" + descriptors else "") packageFragment.fqName.asString() + (if (descriptors.isNotEmpty()) "\n\n" + descriptors else "")
} }
KotlinTestUtils.assertEqualsToFile(File(path, "result.txt"), expected) KotlinTestUtils.assertEqualsToFile(File(path, "result.txt"), expected)
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* * that can be found in the license/LICENSE.txt file.
* 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.android.synthetic.test package org.jetbrains.kotlin.android.synthetic.test
@@ -35,8 +24,6 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.utils.KotlinPaths
import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import java.io.File import java.io.File
@@ -52,7 +39,9 @@ fun KtUsefulTestCase.createTestEnvironment(configuration: CompilerConfiguration,
ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(true, CacheImplementation.DEFAULT)) ExpressionCodegenExtension.registerExtension(project, CliAndroidExtensionsExpressionCodegenExtension(true, CacheImplementation.DEFAULT))
StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor()) StorageComponentContainerContributor.registerExtension(project, AndroidExtensionPropertiesComponentContainerContributor())
ClassBuilderInterceptorExtension.registerExtension(project, CliAndroidOnDestroyClassBuilderInterceptorExtension(CacheImplementation.DEFAULT)) ClassBuilderInterceptorExtension.registerExtension(
project, CliAndroidOnDestroyClassBuilderInterceptorExtension(CacheImplementation.DEFAULT)
)
PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(true)) PackageFragmentProviderExtension.registerExtension(project, CliAndroidPackageFragmentProviderExtension(true))
addAndroidExtensionsRuntimeLibrary(myEnvironment) addAndroidExtensionsRuntimeLibrary(myEnvironment)
@@ -68,5 +57,7 @@ fun addAndroidExtensionsRuntimeLibrary(environment: KotlinCoreEnvironment) {
} }
fun getResPaths(path: String): List<String> { fun getResPaths(path: String): List<String> {
return File(path).listFiles { it -> it.name.startsWith("res") && it.isDirectory }!!.map { "$path${it.name}/" } return File(path)
} .listFiles { file -> file.name.startsWith("res") && file.isDirectory }!!
.map { "$path${it.name}/" }
}