Merge master into idea14

Conflicts:
	.idea/runConfigurations/All_Tests.xml
	idea/src/org/jetbrains/jet/plugin/conversion/copy/ConvertJavaCopyPastePostProcessor.kt
	idea/tests/org/jetbrains/jet/plugin/refactoring/introduce/introduceVariable/AbstractJetExtractionTest.kt
	idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt

Original commit: a0e45e9a12
This commit is contained in:
Nikolay Krasko
2014-06-25 16:26:01 +04:00
54 changed files with 467 additions and 37 deletions
@@ -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<Pair<String, File>> moduleIdsAndFiles = new ArrayList<Pair<String, File>>();
Map<String, File> outDirectories = new HashMap<String, File>();
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<String, File>(targetId, new File(file)));
}
}
cache.clearCacheForRemovedFiles(moduleIdsAndFiles, outDirectories);
boolean significantChanges = false;
@@ -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
@@ -36,6 +35,10 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName
import java.util.HashSet
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 {
@@ -54,16 +57,15 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
if (classNameAndHeader == null) return false
val (className, header) = classNameAndHeader
val classFqName = className.getFqNameForClassNameWithoutDollars()
val annotationDataEncoded = header.annotationData
if (annotationDataEncoded != null) {
val data = BitEncoding.decodeBytes(annotationDataEncoded)
when (header.kind) {
KotlinClassHeader.Kind.PACKAGE_FACADE -> {
return protoMap.put(moduleId, classFqName.parent(), data)
return protoMap.put(moduleId, className, data)
}
KotlinClassHeader.Kind.CLASS -> {
return protoMap.put(moduleId, classFqName, data)
return protoMap.put(moduleId, className, data)
}
else -> {
throw IllegalStateException("Unexpected kind with annotationData: ${header.kind}")
@@ -73,14 +75,19 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
if (header.syntheticClassKind == JvmAnnotationNames.KotlinSyntheticClass.Kind.PACKAGE_PART) {
assert(sourceFiles.size == 1) { "Package part from several source files: $sourceFiles" }
packagePartMap.putPackagePartSourceData(moduleId, sourceFiles.first(), className)
return constantsMap.process(className, fileBytes)
return constantsMap.process(moduleId, sourceFiles.first(), fileBytes)
}
return false
}
public fun clearCacheForRemovedFile(moduleId: String, sourceFile: File) {
packagePartMap.remove(moduleId, sourceFile)
public fun clearCacheForRemovedFiles(moduleIdsAndFiles: Collection<Pair<String, File>>, outDirectories: Map<String, File>) {
for ((moduleId, sourceFile) in moduleIdsAndFiles) {
constantsMap.remove(moduleId, sourceFile)
packagePartMap.remove(moduleId, sourceFile)
}
protoMap.clearOutdated(outDirectories)
}
public override fun getRemovedPackageParts(moduleId: String, compiledSourceFilesToFqName: Map<File, String>): Collection<String> {
@@ -88,7 +95,7 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
}
public override fun getPackageData(moduleId: String, fqName: String): ByteArray? {
return protoMap[moduleId, fqName]
return protoMap[moduleId, JvmClassName.byFqNameWithoutInnerClasses(PackageClassUtils.getPackageClassFqName(FqName(fqName)))]
}
public fun close() {
@@ -98,18 +105,23 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
}
private inner class ProtoMap {
private val map: PersistentMap<String, ByteArray> = PersistentHashMap(
private val map: PersistentHashMap<String, ByteArray> = PersistentHashMap(
File(baseDir, PROTO_MAP),
EnumeratorStringDescriptor(),
ByteArrayExternalizer
)
private fun getKeyString(moduleId: String, fqName: FqName): String {
return moduleId + ":" + fqName
private fun getKeyString(moduleId: String, className: JvmClassName): String {
return moduleId + ":" + className.getInternalName()
}
public fun put(moduleId: String, fqName: FqName, data: ByteArray): Boolean {
val key = getKeyString(moduleId, fqName)
private fun parseKeyString(key: String): Pair<String, JvmClassName> {
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]
if (Arrays.equals(data, oldData)) {
return false
@@ -118,8 +130,29 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
return true
}
public fun get(moduleId: String, fqName: String): ByteArray? {
return map[getKeyString(moduleId, FqName(fqName))]
public fun get(moduleId: String, className: JvmClassName): ByteArray? {
return map[getKeyString(moduleId, className)]
}
public fun clearOutdated(outDirectories: Map<String, File>) {
val keysToRemove = HashSet<String>()
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() {
@@ -134,6 +167,10 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
ConstantsMapExternalizer
)
private fun getKey(moduleId: String, sourceFile: File): String {
return moduleId + File.pathSeparator + sourceFile.getAbsolutePath()
}
private fun getConstantsMap(bytes: ByteArray): Map<String, Any> {
val result = HashMap<String, Any>()
@@ -149,12 +186,12 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
return result
}
public fun process(packagePartClass: JvmClassName, bytes: ByteArray): Boolean {
return put(packagePartClass, getConstantsMap(bytes))
public fun process(moduleId: String, file: File, bytes: ByteArray): Boolean {
return put(moduleId, file, getConstantsMap(bytes))
}
private fun put(packagePartClass: JvmClassName, constantsMap: Map<String, Any>): Boolean {
val key = packagePartClass.getInternalName()
private fun put(moduleId: String, file: File, constantsMap: Map<String, Any>): Boolean {
val key = getKey(moduleId, file)
val oldMap = map[key]
if (oldMap == constantsMap) {
@@ -164,6 +201,10 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
return true
}
public fun remove(moduleId: String, file: File) {
map.remove(getKey(moduleId, file))
}
public fun close() {
map.close()
}
@@ -203,7 +244,7 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
override fun read(`in`: DataInput): Map<String, Any>? {
val size = `in`.readInt()
val map = HashMap<String, Any>(size)
val map = Maps.newHashMapWithExpectedSize<String, Any>(size)!!
for (i in size.indices) {
val name = IOUtil.readString(`in`)!!
@@ -273,6 +314,24 @@ public class IncrementalCacheImpl(val baseDir: File): IncrementalCache {
return result
}
public fun getModulesToPackages(): MultiMap<String, FqName> {
val result = MultiMap.createSet<String, FqName>()
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()
}
@@ -88,10 +88,10 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() {
val haveFilesWithNumbers = testDataDir.listFiles { it.getName().matches(".+\\.(new|delete)\\.\\d+$") }?.isNotEmpty() ?: false
if (haveFilesWithoutNumbers && haveFilesWithNumbers) {
fail("Bad test data format: no files ending with \".new\" or \".delete\" found")
fail("Bad test data format: files ending with both unnumbered and numbered \".new\"/\".delete\" were found")
}
if (!haveFilesWithoutNumbers && !haveFilesWithNumbers) {
fail("Bad test data format: files ending with both unnumbered and numbered \".new\"/\".delete\" were found")
fail("Bad test data format: no files ending with \".new\" or \".delete\" found")
}
if (haveFilesWithoutNumbers) {
@@ -111,7 +111,7 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() {
rebuild()
assertEqualDirectories(outDir, outAfterMake, { it.name == "script.xml" })
assertEqualDirectories(outDir, outAfterMake)
FileUtil.delete(outAfterMake)
}
@@ -187,7 +187,16 @@ public abstract class AbstractIncrementalJpsTest : JpsBuildTestCase() {
private class ModifyContent(name: String, val dataFile: File) : Modification(name) {
override fun perform(workDir: File) {
dataFile.copyTo(File(workDir, "src/$name"))
val file = File(workDir, "src/$name")
val oldLastModified = file.lastModified()
dataFile.copyTo(file)
val newLastModified = file.lastModified()
if (newLastModified <= oldLastModified) {
//Mac OS and some versions of Linux truncate timestamp to nearest second
file.setLastModified(oldLastModified + 1000)
}
}
}
@@ -32,10 +32,20 @@ import org.jetbrains.jet.jps.build.AbstractIncrementalJpsTest;
@SuppressWarnings("all")
@TestMetadata("jps-plugin/testData/incremental")
public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest {
@TestMetadata("allConstants")
public void testAllConstants() throws Exception {
doTest("jps-plugin/testData/incremental/allConstants/");
}
public void testAllFilesPresentInIncremental() throws Exception {
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/");
@@ -56,11 +66,31 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest {
doTest("jps-plugin/testData/incremental/constantValue/");
}
@TestMetadata("dependencyClassReferenced")
public void testDependencyClassReferenced() throws Exception {
doTest("jps-plugin/testData/incremental/dependencyClassReferenced/");
}
@TestMetadata("filesExchangePackages")
public void testFilesExchangePackages() throws Exception {
doTest("jps-plugin/testData/incremental/filesExchangePackages/");
}
@TestMetadata("independentClasses")
public void testIndependentClasses() throws Exception {
doTest("jps-plugin/testData/incremental/independentClasses/");
}
@TestMetadata("multiplePackagesModified")
public void testMultiplePackagesModified() throws Exception {
doTest("jps-plugin/testData/incremental/multiplePackagesModified/");
}
@TestMetadata("ourClassReferenced")
public void testOurClassReferenced() throws Exception {
doTest("jps-plugin/testData/incremental/ourClassReferenced/");
}
@TestMetadata("packageFileAdded")
public void testPackageFileAdded() throws Exception {
doTest("jps-plugin/testData/incremental/packageFileAdded/");
@@ -86,6 +116,21 @@ 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/");
}
@TestMetadata("returnTypeChanged")
public void testReturnTypeChanged() throws Exception {
doTest("jps-plugin/testData/incremental/returnTypeChanged/");
@@ -96,6 +141,11 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest {
doTest("jps-plugin/testData/incremental/simpleClassDependency/");
}
@TestMetadata("soleFileChangesPackage")
public void testSoleFileChangesPackage() throws Exception {
doTest("jps-plugin/testData/incremental/soleFileChangesPackage/");
}
@TestMetadata("topLevelFunctionSameSignature")
public void testTopLevelFunctionSameSignature() throws Exception {
doTest("jps-plugin/testData/incremental/topLevelFunctionSameSignature/");
@@ -39,7 +39,7 @@ import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass
fun File.hash() = Files.hash(this, Hashing.crc32())
fun getDirectoryString(dir: File, interestingPaths: List<String>, ignore: (File) -> Boolean): String {
fun getDirectoryString(dir: File, interestingPaths: List<String>): String {
val buf = StringBuilder()
val p = Printer(buf)
@@ -52,10 +52,6 @@ fun getDirectoryString(dir: File, interestingPaths: List<String>, ignore: (File)
val children = listFiles!!.toList().sortBy { it.getName() }.sortBy { it.isDirectory() }
for (child in children) {
if (ignore(child)) {
continue
}
if (child.isDirectory()) {
p.println(child.name)
addDirContent(child)
@@ -82,10 +78,10 @@ fun getDirectoryString(dir: File, interestingPaths: List<String>, ignore: (File)
return buf.toString()
}
fun getAllRelativePaths(dir: File, ignore: (File) -> Boolean): Set<String> {
fun getAllRelativePaths(dir: File): Set<String> {
val result = HashSet<String>()
FileUtil.processFilesRecursively(dir) {
if (it!!.isFile() && !ignore(it)) {
if (it!!.isFile()) {
result.add(FileUtil.getRelativePath(dir, it)!!)
}
@@ -95,16 +91,16 @@ fun getAllRelativePaths(dir: File, ignore: (File) -> Boolean): Set<String> {
return result
}
fun assertEqualDirectories(expected: File, actual: File, ignore: (File) -> Boolean) {
val pathsInExpected = getAllRelativePaths(expected, ignore)
val pathsInActual = getAllRelativePaths(actual, ignore)
fun assertEqualDirectories(expected: File, actual: File) {
val pathsInExpected = getAllRelativePaths(expected)
val pathsInActual = getAllRelativePaths(actual)
val changedPaths = Sets.intersection(pathsInExpected, pathsInActual)
.filter { !Arrays.equals(File(expected, it).readBytes(), File(actual, it).readBytes()) }
.sort()
val expectedString = getDirectoryString(expected, changedPaths, ignore)
val actualString = getDirectoryString(actual, changedPaths, ignore)
val expectedString = getDirectoryString(expected, changedPaths)
val actualString = getDirectoryString(actual, changedPaths)
assertEquals(expectedString, actualString)
}
@@ -0,0 +1,22 @@
Cleaning output files:
out/production/module/test/TestPackage-const-*.class
out/production/module/test/TestPackage.class
End of files
Compiling files:
src/const.kt
End of files
Cleaning output files:
out/production/module/test/TestPackage-const-*.class
out/production/module/test/TestPackage.class
End of files
Compiling files:
src/const.kt
End of files
Cleaning output files:
out/production/module/test/Usage.class
End of files
Compiling files:
src/usage.kt
End of files
@@ -0,0 +1,12 @@
package test
val b: Byte = 100
val s: Short = 20000
val i: Int = 2000000
val l: Long = 2000000000000L
val f: Float = 3.14f
val d: Double = 3.14
val bb: Boolean = true
val c: Char = '\u03c0' // pi symbol
val str: String = ":)"
@@ -0,0 +1,12 @@
package test
val b: Byte = 50 + 50
val s: Short = 10000 + 10000
val i: Int = 1000000 + 1000000
val l: Long = 1000000000000L + 1000000000000L
val f: Float = 0.0f + 3.14f
val d: Double = 0.0 + 3.14
val bb: Boolean = !false
val c: Char = '\u03c0' // pi symbol
val str: String = ":)"
@@ -0,0 +1,12 @@
package test
val b: Byte = 0
val s: Short = 0
val i: Int = 0
val l: Long = 0
val f: Float = 0.0f
val d: Double = 0.0
val bb: Boolean = false
val c: Char = 'x'
val str: String = ":("
@@ -0,0 +1,4 @@
package test
deprecated("$b $s $i $l $f $d $bb $c $str")
class Usage
@@ -0,0 +1,3 @@
package test
class A
@@ -0,0 +1,3 @@
package test
class A
@@ -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
@@ -0,0 +1,4 @@
package test
fun other() {
}
@@ -0,0 +1,6 @@
package test
fun a(ref: kotlin.test.Asserter) {
b(ref)
println(":)")
}
@@ -0,0 +1,6 @@
package test
fun a(ref: kotlin.test.Asserter) {
b(ref)
println(":)")
}
@@ -0,0 +1,6 @@
package test
fun b(ref: kotlin.test.Asserter) {
a(ref)
println(":)")
}
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,3 @@
package foo
fun a() = "a"
@@ -0,0 +1,3 @@
package foo
fun b() = "b"
@@ -0,0 +1,3 @@
package bar
fun b() = "b"
@@ -0,0 +1,17 @@
Cleaning output files:
out/production/module/bar/BarPackage-c-*.class
out/production/module/bar/BarPackage.class
out/production/module/foo/FooPackage-b-*.class
out/production/module/foo/FooPackage.class
End of files
Compiling files:
src/b.kt
src/c.kt
End of files
Cleaning output files:
out/production/module/foo/FooPackage-a-*.class
out/production/module/foo/FooPackage.class
End of files
Compiling files:
src/a.kt
End of files
@@ -0,0 +1,3 @@
package bar
fun c() = "c"
@@ -0,0 +1,3 @@
package foo
fun c() = "c"
@@ -0,0 +1,3 @@
package a
fun a1() = ":)"
@@ -0,0 +1,3 @@
package a
fun a2() = ":))"
@@ -0,0 +1,3 @@
package b
fun b1() = ":("
@@ -0,0 +1,3 @@
package b
fun b2() = ":(("
@@ -0,0 +1,17 @@
Cleaning output files:
out/production/module/b/BPackage-b2-*.class
out/production/module/b/BPackage.class
End of files
Compiling files:
src/a2.kt
End of files
Cleaning output files:
out/production/module/a/APackage-a1-*.class
out/production/module/a/APackage.class
out/production/module/b/BPackage-b1-*.class
out/production/module/b/BPackage.class
End of files
Compiling files:
src/a1.kt
src/b1.kt
End of files
@@ -0,0 +1,3 @@
package klass
class Klass
@@ -0,0 +1,3 @@
package klass
class Klass
@@ -0,0 +1,8 @@
package test
import klass.*
fun a(klass: Klass) {
b(klass)
println(":)")
}
@@ -0,0 +1,8 @@
package test
import klass.*
fun a(klass: Klass) {
b(klass)
println(":)")
}
@@ -0,0 +1,8 @@
package test
import klass.*
fun a(klass: Klass) {
b(klass)
println(":)")
}
@@ -0,0 +1,8 @@
package test
import klass.*
fun b(klass: Klass) {
a(klass)
println(":)")
}
@@ -0,0 +1,18 @@
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
Cleaning output files:
out/production/module/klass/Klass.class
out/production/module/test/TestPackage-a-*.class
out/production/module/test/TestPackage.class
End of files
Compiling files:
src/Klass.kt
src/a.kt
End of files
@@ -0,0 +1,3 @@
package test
fun a() = "a"
@@ -0,0 +1,3 @@
package test
fun b() = "b"
@@ -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
@@ -0,0 +1,3 @@
package test
fun a() = "a"
@@ -0,0 +1,3 @@
package test2
fun a() = "a"
@@ -0,0 +1,3 @@
package test
fun b() = "b"
@@ -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
@@ -0,0 +1,3 @@
package test
fun a() = "a"
@@ -0,0 +1,3 @@
package test
fun b() = "b"
@@ -0,0 +1,9 @@
Cleaning output files:
out/production/module/test/TestPackage-a-*.class
out/production/module/test/TestPackage.class
End of files
Cleaning output files:
out/production/module/test/TestPackage-b-*.class
End of files
Compiling files:
End of files
@@ -0,0 +1,3 @@
package foo
fun a() = "a"
@@ -0,0 +1,4 @@
package bar
fun a() = "a"
fun aa() = "aa"
@@ -0,0 +1,7 @@
Cleaning output files:
out/production/module/foo/FooPackage-a-*.class
out/production/module/foo/FooPackage.class
End of files
Compiling files:
src/a.kt
End of files