diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputer.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputer.kt index 7121387fb56..043db0021f4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputer.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputer.kt @@ -68,33 +68,37 @@ object ClasspathChangesComputer { /** * Maps the unchanged snapshot files of the current build to the unchanged snapshot files of the previous build (selected from all the * snapshot files of the previous build). + * + * Note that the unchanged files of the current build were detected by Gradle, so a mapping must exist for each of them, we only have to + * find it. + * + * IMPORTANT: The alignment algorithm must use the same input normalization that is used for snapshot files in the Gradle task. + * Currently, snapshot files are annotated with `@Classpath` and are regular files (not jars), so (only) their contents and order + * matter. */ private fun alignUnchangedSnapshotFiles(unchangedCurrentSnapshotFiles: List, previousSnapshotFiles: List): Map { - var index = 0 + val sizeToPreviousFiles: Map>> = previousSnapshotFiles.withIndex().groupBy { it.value.length() } + + var startIndexToSearch = 0 return unchangedCurrentSnapshotFiles.associateWith { unchangedCurrentFile -> - var candidates = previousSnapshotFiles.subList(index, previousSnapshotFiles.size).filter { previousFile -> - unchangedCurrentFile.lastModified() == previousFile.lastModified() && unchangedCurrentFile.length() == previousFile.length() + val candidates = (sizeToPreviousFiles[unchangedCurrentFile.length()] ?: emptyList()).filter { it.index >= startIndexToSearch } + val unchangedPreviousFileWithIndex: IndexedValue = if (candidates.size == 1) { + // A matching file must exist, so if there is only one candidate, it is the one. + candidates.single() + } else { + // If there are multiple matching files, select the first one. (Even if it doesn't match Gradle's alignment, it is still a + // correct alignment.) + val unchangedContents = unchangedCurrentFile.readBytes() + candidates.firstOrNull { candidate -> + unchangedContents.contentEquals(candidate.value.readBytes()) + } ?: error("Can't find previous snapshot file of unchanged current snapshot file '${unchangedCurrentFile.path}'") } - if (candidates.size > 1) { - candidates = candidates.filter { candidate -> - unchangedCurrentFile.readBytes().contentEquals(candidate.readBytes()) - } - } - check(candidates.isNotEmpty()) { - "Can't find previous snapshot file of unchanged current snapshot file '${unchangedCurrentFile.path}'" - } - // If there are multiple candidates, select the first one. (It doesn't have to match Gradle's alignment as long as it's still a - // correct alignment.) - val unchangedPreviousFile = candidates.first() - while (previousSnapshotFiles[index] != unchangedPreviousFile) { - index++ - } - index++ - unchangedPreviousFile + startIndexToSearch = unchangedPreviousFileWithIndex.index + 1 + unchangedPreviousFileWithIndex.value } } - /** Returns `true` if this snapshot file contains a duplicate class with another snapshot file in the given set. */ + /** Returns `true` if this snapshot file contains a duplicate class with another snapshot file in the given list. */ @Suppress("unused", "UNUSED_PARAMETER") private fun File.containsDuplicatesWith(otherSnapshotFiles: List): Boolean { // TODO: Implement and optimize this method @@ -129,8 +133,8 @@ object ClasspathChangesComputer { // - Add previous class snapshots to incrementalJvmCache. // - Internally, incrementalJvmCache maintains a set of dirty classes to detect removed classes. Add previous classes to this set // to detect removed classes later (see step 2). - // - The final ChangesCollector result will contain all symbols in the previous classes (we actually don't need them, but it's - // part of the API's effects). + // - The ChangesCollector result will contain symbols in the previous classes (we actually don't need them, but it's part of the + // API's effects). val unusedChangesCollector = ChangesCollector() for (previousSnapshot in previousClassSnapshots) { when (previousSnapshot) { @@ -161,13 +165,11 @@ object ClasspathChangesComputer { // Step 2: // - Add current class snapshots to incrementalJvmCache. This will overwrite any previous class snapshots that have the same - // `JvmClassName`. The previous class snapshots that are not overwritten will be detected as removed class snapshots and will be - // removed from incrementalJvmCache in step 3. - // - Internally, incrementalJvmCache will mark these classes as non-dirty. That means unchanged/modified classes that were marked - // as dirty in step 1 will now be non-dirty (added classes will also be marked as non-dirty even though they were not marked as - // dirty before). After this, the remaining dirty classes will be removed classes. - // - The intermediate ChangesCollector result will contain all symbols in added classes and changed (added/modified/removed) - // symbols in modified classes. We will collect all symbols in removed classes in step 3. + // `JvmClassName`. The remaining previous class snapshots will be removed in step 3. + // - Internally, incrementalJvmCache will remove current classes from the set of dirty classes. After this, the remaining dirty + // classes will be classes that are present on the previous classpath but not on the current classpath (i.e., removed classes). + // - The intermediate ChangesCollector result will contain symbols in added classes and changed (added/modified/removed) symbols + // in modified classes. We will collect symbols in removed classes in step 3. val changesCollector = ChangesCollector() for (currentSnapshot in currentClassSnapshots) { when (currentSnapshot) { @@ -195,10 +197,10 @@ object ClasspathChangesComputer { } // Step 3: - // - Detect removed classes: they are the remaining dirty classes. - // - Remove previous class snapshots of removed classes from incrementalJvmCache. - // - The final ChangesCollector result will contain all symbols in added classes, changed (added/modified/removed) symbols in - // modified classes, and all symbols in removed classes. + // - Detect removed classes: They are the remaining dirty classes. + // - Remove class snapshots of removed classes from incrementalJvmCache. + // - The final ChangesCollector result will contain symbols in added classes, changed (added/modified/removed) symbols in modified + // classes, and symbols in removed classes. incrementalJvmCache.clearCacheForRemovedClasses(changesCollector) // Normalize the changes and clean up diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 71f32578689..75e7045f978 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -831,15 +831,25 @@ abstract class KotlinCompile @Inject constructor( return if (fileChanges.isEmpty()) { ClasspathChanges.Available(LinkedHashSet(), LinkedHashSet()) } else { - val currentClasspathEntrySnapshotFiles = classpathSnapshotProperties.classpathSnapshot.files.toList() - val changedCurrentFiles = fileChanges - .filter { it.changeType == ChangeType.ADDED || it.changeType == ChangeType.MODIFIED } - .map { it.file }.toSet() - ClasspathChangesComputer.compute( - currentClasspathEntrySnapshotFiles = currentClasspathEntrySnapshotFiles, - previousClasspathEntrySnapshotFiles = getPreviousClasspathEntrySnapshotFiles(), - unchangedCurrentClasspathEntrySnapshotFiles = currentClasspathEntrySnapshotFiles.filter { it !in changedCurrentFiles } - ) + val previousClasspathEntrySnapshotFiles = getPreviousClasspathEntrySnapshotFiles() + if (previousClasspathEntrySnapshotFiles.isEmpty()) { + // When this happens, it means that either the previous classpath was empty or there were no source files to compile in the + // previous non-incremental run so the task action was skipped and the classpath snapshot directory was not populated (see + // AbstractKotlinCompile.executeImpl). + // We could improve this handling, but it's fine to return `UnableToCompute` here as it's likely that there are also no + // source files to compile/recompile in this incremental run. + ClasspathChanges.NotAvailable.UnableToCompute + } else { + val currentClasspathEntrySnapshotFiles = classpathSnapshotProperties.classpathSnapshot.files.toList() + val changedCurrentFiles = fileChanges + .filter { it.changeType == ChangeType.ADDED || it.changeType == ChangeType.MODIFIED } + .map { it.file }.toSet() + ClasspathChangesComputer.compute( + currentClasspathEntrySnapshotFiles = currentClasspathEntrySnapshotFiles, + previousClasspathEntrySnapshotFiles = previousClasspathEntrySnapshotFiles, + unchangedCurrentClasspathEntrySnapshotFiles = currentClasspathEntrySnapshotFiles.filter { it !in changedCurrentFiles } + ) + } } } @@ -859,10 +869,7 @@ abstract class KotlinCompile @Inject constructor( classpathSnapshotDir.deleteRecursively() classpathSnapshotDir.mkdirs() snapshotFiles.forEachIndexed { index, snapshotFile -> - val targetFile = File("$classpathSnapshotDir/$index/${snapshotFile.name}") - snapshotFile.copyTo(targetFile, overwrite = true) - // Preserve timestamp to find out unchanged files later (see `ClasspathChangesComputer.alignUnchangedSnapshotFiles`) - targetFile.setLastModified(snapshotFile.lastModified()) + snapshotFile.copyTo(File("$classpathSnapshotDir/$index/${snapshotFile.name}")) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputerTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputerTest.kt index 0fa7b911ef4..30ece09f761 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputerTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathChangesComputerTest.kt @@ -83,12 +83,20 @@ class KotlinClassesClasspathChangesComputerTest : ClasspathChangesComputerTest() LookupSymbol(name = "b3", scope = "com.example.B"), LookupSymbol(name = "b4", scope = "com.example.B"), LookupSymbol(name = "C", scope = "com.example"), - LookupSymbol(name = "D", scope = "com.example") + LookupSymbol(name = "D", scope = "com.example"), + LookupSymbol(name = SAM_LOOKUP_NAME.asString(), scope = "com.example"), + LookupSymbol(name = "topLevelFuncB", scope = "com.example"), + LookupSymbol(name = "topLevelFuncC", scope = "com.example"), + LookupSymbol(name = "topLevelFuncD", scope = "com.example"), + LookupSymbol(name = "topLevelFuncInCKtMovedToDKt", scope = "com.example"), + LookupSymbol(name = "CKt", scope = "com.example"), ), fqNames = setOf( FqName("com.example.B"), FqName("com.example.C"), - FqName("com.example.D") + FqName("com.example.D"), + FqName("com.example"), + FqName("com.example.CKt"), ) ), changes @@ -169,18 +177,21 @@ private fun snapshotClasspath(classpathSourceDir: File, tmpDir: TemporaryFolder) .sortedBy { it } val sourceFiles = relativePathsInDir.map { relativePath -> if (relativePath.endsWith(".kt")) { + val preCompiledClassFilesRoot = classpathEntrySourceDir.path.let { + File(it.substringBeforeLast("src") + "classes" + it.substringAfterLast("src")) + }.also { check(it.exists()) } KotlinSourceFile( classpathEntrySourceDir, relativePath, - preCompiledClassFile = ClassFile( - File(classpathEntrySourceDir.path.replace("src/kotlin", "classes/kotlin")), - relativePath.replace(".kt", ".class") - ) + preCompiledClassFiles = listOf( + ClassFile(preCompiledClassFilesRoot, relativePath.replace(".kt", ".class")), + ClassFile(preCompiledClassFilesRoot, relativePath.replace(".kt", "Kt.class")) + ).filter { File(it.classRoot, it.unixStyleRelativePath).exists() } ) } else { SourceFile(classpathEntrySourceDir, relativePath) } } - val classFiles = sourceFiles.map { TestSourceFile(it, tmpDir).compile() } + val classFiles = sourceFiles.flatMap { TestSourceFile(it, tmpDir).compileAll() } ClasspathEntrySnapshot( classSnapshots = classFiles.map { it.unixStyleRelativePath to it.snapshot() }.toMap(LinkedHashMap()) ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathSnapshotTestCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathSnapshotTestCommon.kt index 269258f9526..56669f09d3c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathSnapshotTestCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/incremental/ClasspathSnapshotTestCommon.kt @@ -36,7 +36,12 @@ abstract class ClasspathSnapshotTestCommon { fun asFile() = File(baseDir, unixStyleRelativePath) } - class KotlinSourceFile(baseDir: File, relativePath: String, val preCompiledClassFile: ClassFile) : SourceFile(baseDir, relativePath) + class KotlinSourceFile(baseDir: File, relativePath: String, val preCompiledClassFiles: List) : + SourceFile(baseDir, relativePath) { + + constructor(baseDir: File, relativePath: String, preCompiledClassFile: ClassFile) : + this(baseDir, relativePath, listOf(preCompiledClassFile)) + } /** Same as [SourceFile] but with a [TemporaryFolder] to store the results of operations on the [SourceFile]. */ open class TestSourceFile(val sourceFile: SourceFile, private val tmpDir: TemporaryFolder) { @@ -73,12 +78,25 @@ abstract class ClasspathSnapshotTestCommon { } private fun compileKotlin(): List { - // TODO: Call Kotlin compiler to generate classes, for example: - // org.jetbrains.kotlin.test.MockLibraryUtil.compileKotlin(sourceFile.asFile().path, sourceFile.preCompiledClassFile.classRoot) - // However, currently it is not possible (see https://github.com/JetBrains/kotlin/pull/4512#discussion_r679432232), so we use - // the precompiled classes in the test data instead. sourceFile as KotlinSourceFile - return listOf(sourceFile.preCompiledClassFile) + + // TODO: Call Kotlin compiler to generate classes. + // If /dist/kotlinc/lib/kotlin-compiler.jar is available (e.g., by running ./gradlew dist), we will be able to + // call the Kotlin compiler to generate classes from here. For example: +// val classesDir = tmpDir.newFolder() +// org.jetbrains.kotlin.test.MockLibraryUtil.compileKotlin(sourceFile.asFile().path, classesDir) +// val classFiles = classesDir.walk() +// .filter { it.isFile && !it.toRelativeString(classesDir).startsWith("META-INF/") } +// .map { ClassFile(classesDir, it.toRelativeString(classesDir)) } +// .sortedBy { it.unixStyleRelativePath.substringBefore(".class") } +// .toList() +// kotlin.test.assertEquals(classFiles.size, sourceFile.preCompiledClassFiles.size) +// sourceFile.preCompiledClassFiles.forEach { +// File(classesDir, it.unixStyleRelativePath).copyTo(File(it.classRoot, it.unixStyleRelativePath), overwrite = true) +// } + // However, kotlin-compiler.jar is currently not available in CI builds, so we need to pre-compile the classes, put them in the + // test data, and use them here instead. + return sourceFile.preCompiledClassFiles } private fun compileJava(): List { diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/AKt.class b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/AKt.class new file mode 100644 index 00000000000..09c24e7031d Binary files /dev/null and b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/AKt.class differ diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/BKt.class b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/BKt.class new file mode 100644 index 00000000000..09018cf01f6 Binary files /dev/null and b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/BKt.class differ diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/DKt.class b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/DKt.class new file mode 100644 index 00000000000..e53ac2131d2 Binary files /dev/null and b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/current-classpath/0/com/example/DKt.class differ diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/AKt.class b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/AKt.class new file mode 100644 index 00000000000..33ec1a04f0c Binary files /dev/null and b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/AKt.class differ diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/BKt.class b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/BKt.class new file mode 100644 index 00000000000..aa8b03d5b71 Binary files /dev/null and b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/BKt.class differ diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/CKt.class b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/CKt.class new file mode 100644 index 00000000000..9e797e17994 Binary files /dev/null and b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/classes/kotlin/previous-classpath/0/com/example/CKt.class differ diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/java/previous-classpath/0/com/example/C.java b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/java/previous-classpath/0/com/example/C.java index cfcbdb5df26..cb58175056b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/java/previous-classpath/0/com/example/C.java +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/java/previous-classpath/0/com/example/C.java @@ -1,6 +1,6 @@ package com.example; -// Will be removed +// To-be-removed class public class C { public int c = 0; } diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/A.kt b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/A.kt index 904b2c39229..fe3ff84c843 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/A.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/A.kt @@ -4,3 +4,6 @@ package com.example class A { val a: Int = 0 } + +// Unchanged top-level function +fun topLevelFuncA() {} diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/B.kt b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/B.kt index e7ae7bdbdda..e7514c83f08 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/B.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/B.kt @@ -7,3 +7,6 @@ public class B { //val b3: Int = 0 // Removed field val b4: Int = 0 // Added field } + +// Modified top-level function +fun topLevelFuncB(): Int = 0 diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/D.kt b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/D.kt index e0b6460e1e7..11f0fea4a63 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/D.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/current-classpath/0/com/example/D.kt @@ -4,3 +4,9 @@ package com.example public class D { val d: Int = 0 } + +// Added top-level function +fun topLevelFuncD() {} + +// Moved top-level function +fun topLevelFuncInCKtMovedToDKt() {} diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/A.kt b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/A.kt index 409c5326b3c..f780796b9f4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/A.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/A.kt @@ -3,3 +3,5 @@ package com.example class A { val a: Int = 0 } + +fun topLevelFuncA() {} diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/B.kt b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/B.kt index 2bcee31626a..73e28502dcf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/B.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/B.kt @@ -5,3 +5,5 @@ public class B { val b2: Int = 0 val b3: Int = 0 } + +fun topLevelFuncB() {} diff --git a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/C.kt b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/C.kt index 6193de47875..f902cb1b522 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/C.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/testData/ClasspathChangesComputerTest/testMultipleClasses/src/kotlin/previous-classpath/0/com/example/C.kt @@ -1,6 +1,12 @@ package com.example -// Will be removed +// To-be-removed class public class C { val c: Int = 0 } + +// To-be-removed top-level function +fun topLevelFuncC() {} + +// To-be-moved top-level function +fun topLevelFuncInCKtMovedToDKt() {}