diff --git a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java index 8faa3f15c23..853be538fc2 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java +++ b/jps-plugin/src/org/jetbrains/jet/jps/build/KotlinBuilder.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.jps.build; +import com.google.common.collect.Lists; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.StreamUtil; @@ -23,6 +24,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; +import kotlin.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.cli.common.KotlinVersion; import org.jetbrains.jet.cli.common.arguments.CommonCompilerArguments; @@ -222,11 +224,18 @@ public class KotlinBuilder extends ModuleLevelBuilder { IncrementalCacheImpl cache = new IncrementalCacheImpl(KotlinBuilderModuleScriptGenerator.getIncrementalCacheDir(context)); try { + List> moduleIdsAndFiles = Lists.newArrayList(); + Map outDirectories = new HashMap(); + for (ModuleBuildTarget target : chunk.getTargets()) { + String targetId = target.getId(); + outDirectories.put(targetId, target.getOutputDir()); + for (String file : dirtyFilesHolder.getRemovedFiles(target)) { - cache.clearCacheForRemovedFile(target.getId(), new File(file)); + moduleIdsAndFiles.add(new Pair(targetId, new File(file))); } } + cache.clearCacheForRemovedFiles(moduleIdsAndFiles, outDirectories); boolean significantChanges = false; diff --git a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt index 6a4e2c54947..56a64060821 100644 --- a/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/jet/jps/incremental/IncrementalCacheImpl.kt @@ -17,7 +17,6 @@ package org.jetbrains.jet.jps.incremental import java.io.File -import com.intellij.util.io.PersistentMap import com.intellij.util.io.PersistentHashMap import java.io.DataOutput import com.intellij.util.io.IOUtil @@ -38,6 +37,8 @@ import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalCache import java.util.HashMap import com.google.common.collect.Maps import org.jetbrains.jet.lang.resolve.java.PackageClassUtils +import com.intellij.util.containers.MultiMap +import com.intellij.openapi.util.io.FileUtil public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { class object { @@ -80,9 +81,13 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return false } - public fun clearCacheForRemovedFile(moduleId: String, sourceFile: File) { - constantsMap.remove(moduleId, sourceFile) - packagePartMap.remove(moduleId, sourceFile) + public fun clearCacheForRemovedFiles(moduleIdsAndFiles: Collection>, outDirectories: Map) { + for ((moduleId, sourceFile) in moduleIdsAndFiles) { + constantsMap.remove(moduleId, sourceFile) + packagePartMap.remove(moduleId, sourceFile) + } + + protoMap.clearOutdated(outDirectories) } public override fun getRemovedPackageParts(moduleId: String, compiledSourceFilesToFqName: Map): Collection { @@ -100,7 +105,7 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { } private inner class ProtoMap { - private val map: PersistentMap = PersistentHashMap( + private val map: PersistentHashMap = PersistentHashMap( File(baseDir, PROTO_MAP), EnumeratorStringDescriptor(), ByteArrayExternalizer @@ -110,6 +115,11 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return moduleId + ":" + className.getInternalName() } + private fun parseKeyString(key: String): Pair { + val colon = key.lastIndexOf(":") + return Pair(key.substring(0, colon), JvmClassName.byInternalName(key.substring(colon + 1))) + } + public fun put(moduleId: String, className: JvmClassName, data: ByteArray): Boolean { val key = getKeyString(moduleId, className) val oldData = map[key] @@ -124,6 +134,27 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return map[getKeyString(moduleId, className)] } + public fun clearOutdated(outDirectories: Map) { + val keysToRemove = HashSet() + + map.processKeys { key -> + val (moduleId, className) = parseKeyString(key!!) + val outDir = outDirectories[moduleId] + if (outDir != null) { + val classFile = File(outDir, FileUtil.toSystemDependentName(className.getInternalName()) + ".class") + if (!classFile.exists()) { + keysToRemove.add(key) + } + } + + true + } + + for (key in keysToRemove) { + map.remove(key) + } + } + public fun close() { map.close() } @@ -283,6 +314,24 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache { return result } + public fun getModulesToPackages(): MultiMap { + val result = MultiMap.createSet() + + map.processKeysWithExistingMapping { key -> + val indexOf = key!!.indexOf(File.pathSeparator) + val moduleId = key.substring(0, indexOf) + val packagePartClassName = map[key]!! + + val packageFqName = JvmClassName.byInternalName(packagePartClassName).getFqNameForClassNameWithoutDollars().parent() + + result.putValue(moduleId, packageFqName) + + true + } + + return result + } + public fun close() { map.close() } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java index d91f934ed53..c475e1dda7a 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/IncrementalJpsTestGenerated.java @@ -41,6 +41,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("jps-plugin/testData/incremental"), Pattern.compile("^([^\\.]+)$"), false); } + @TestMetadata("classRecreated") + public void testClassRecreated() throws Exception { + doTest("jps-plugin/testData/incremental/classRecreated/"); + } + @TestMetadata("classSignatureChanged") public void testClassSignatureChanged() throws Exception { doTest("jps-plugin/testData/incremental/classSignatureChanged/"); @@ -101,6 +106,16 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest { doTest("jps-plugin/testData/incremental/packageFilesChangedInTurn/"); } + @TestMetadata("packageRecreated") + public void testPackageRecreated() throws Exception { + doTest("jps-plugin/testData/incremental/packageRecreated/"); + } + + @TestMetadata("packageRecreatedAfterRenaming") + public void testPackageRecreatedAfterRenaming() throws Exception { + doTest("jps-plugin/testData/incremental/packageRecreatedAfterRenaming/"); + } + @TestMetadata("packageRemoved") public void testPackageRemoved() throws Exception { doTest("jps-plugin/testData/incremental/packageRemoved/"); diff --git a/jps-plugin/testData/incremental/classRecreated/A.kt.new.2 b/jps-plugin/testData/incremental/classRecreated/A.kt.new.2 new file mode 100644 index 00000000000..1b0178fd9be --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/A.kt.new.2 @@ -0,0 +1,3 @@ +package test + +class A diff --git a/jps-plugin/testData/incremental/classRecreated/a.kt b/jps-plugin/testData/incremental/classRecreated/a.kt new file mode 100644 index 00000000000..1b0178fd9be --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/a.kt @@ -0,0 +1,3 @@ +package test + +class A diff --git a/jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 b/jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/a.kt.delete.1 @@ -0,0 +1 @@ + diff --git a/jps-plugin/testData/incremental/classRecreated/build.log b/jps-plugin/testData/incremental/classRecreated/build.log new file mode 100644 index 00000000000..d59630c7ce7 --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/build.log @@ -0,0 +1,17 @@ +Cleaning output files: +out/production/module/test/A.class +End of files +Compiling files: +End of files + + +Compiling files: +src/A.kt +End of files +Cleaning output files: +out/production/module/test/TestPackage-other-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/other.kt +End of files \ No newline at end of file diff --git a/jps-plugin/testData/incremental/classRecreated/other.kt b/jps-plugin/testData/incremental/classRecreated/other.kt new file mode 100644 index 00000000000..dc156549ce5 --- /dev/null +++ b/jps-plugin/testData/incremental/classRecreated/other.kt @@ -0,0 +1,4 @@ +package test + +fun other() { +} diff --git a/jps-plugin/testData/incremental/packageRecreated/a.kt b/jps-plugin/testData/incremental/packageRecreated/a.kt new file mode 100644 index 00000000000..30ca24b5576 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/a.kt @@ -0,0 +1,3 @@ +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 b/jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/a.kt.delete.1 @@ -0,0 +1 @@ + diff --git a/jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 b/jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 new file mode 100644 index 00000000000..5c782f47a25 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/b.kt.new.2 @@ -0,0 +1,3 @@ +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/packageRecreated/build.log b/jps-plugin/testData/incremental/packageRecreated/build.log new file mode 100644 index 00000000000..73408189236 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreated/build.log @@ -0,0 +1,11 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +End of files + + +Compiling files: +src/b.kt +End of files diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt new file mode 100644 index 00000000000..30ca24b5576 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt @@ -0,0 +1,3 @@ +package test + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 new file mode 100644 index 00000000000..9d39f81713e --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/a.kt.new.1 @@ -0,0 +1,3 @@ +package test2 + +fun a() = "a" diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 new file mode 100644 index 00000000000..5c782f47a25 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/b.kt.new.2 @@ -0,0 +1,3 @@ +package test + +fun b() = "b" diff --git a/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log new file mode 100644 index 00000000000..7cb5ae7d3e1 --- /dev/null +++ b/jps-plugin/testData/incremental/packageRecreatedAfterRenaming/build.log @@ -0,0 +1,19 @@ +Cleaning output files: +out/production/module/test/TestPackage-a-*.class +out/production/module/test/TestPackage.class +End of files +Compiling files: +src/a.kt +End of files + + +Compiling files: +src/b.kt +End of files +Cleaning output files: +out/production/module/test2/Test2Package-a-*.class +out/production/module/test2/Test2Package.class +End of files +Compiling files: +src/a.kt +End of files