Refine dirty files computation in case of Java source changes

#KT-17621 In Progress
This commit is contained in:
Denis Zharkov
2017-11-30 15:24:52 +03:00
parent 26393d738f
commit ae6421476d
66 changed files with 634 additions and 140 deletions
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
@@ -54,6 +55,7 @@ open class IncrementalJvmCache(
private val DIRTY_OUTPUT_CLASSES = "dirty-output-classes"
private val INLINE_FUNCTIONS = "inline-functions"
private val INTERNAL_NAME_TO_SOURCE = "internal-name-to-source"
private val JAVA_SOURCES_PROTO_MAP = "java-sources-proto-map"
private val MODULE_MAPPING_FILE_NAME = "." + ModuleMapping.MAPPING_FILE_EXT
}
@@ -68,6 +70,7 @@ open class IncrementalJvmCache(
private val inlineFunctionsMap = registerMap(InlineFunctionsMap(INLINE_FUNCTIONS.storageFile))
// todo: try to use internal names only?
private val internalNameToSource = registerMap(InternalNameToSourcesMap(INTERNAL_NAME_TO_SOURCE.storageFile))
private val javaSourcesProtoMap = registerMap(JavaSourcesProtoMap(JAVA_SOURCES_PROTO_MAP.storageFile))
private val outputDir by lazy(LazyThreadSafetyMode.NONE) { requireNotNull(targetOutputDir) { "Target is expected to have output directory" } }
@@ -169,6 +172,28 @@ open class IncrementalJvmCache(
}
}
fun saveJavaClassProto(source: File, serializedJavaClass: SerializedJavaClass, collector: ChangesCollector) {
val jvmClassName = JvmClassName.byClassId(serializedJavaClass.classId)
javaSourcesProtoMap.process(jvmClassName, serializedJavaClass, collector)
sourceToClassesMap.add(source, jvmClassName)
val (proto, nameResolver) = serializedJavaClass.toProtoData()
addToClassStorage(proto, nameResolver, source)
dirtyOutputClassesMap.notDirty(jvmClassName.internalName)
}
fun getObsoleteJavaClasses(): Collection<ClassId> =
dirtyOutputClassesMap.getDirtyOutputClasses()
.mapNotNull {
javaSourcesProtoMap[it]?.classId
}
fun isJavaClassToTrack(classId: ClassId): Boolean {
val jvmClassName = JvmClassName.byClassId(classId)
return dirtyOutputClassesMap.isDirty(jvmClassName.internalName) ||
javaSourcesProtoMap[jvmClassName.internalName] == null
}
fun clearCacheForRemovedClasses(changesCollector: ChangesCollector) {
val dirtyClasses = dirtyOutputClassesMap
.getDirtyOutputClasses()
@@ -203,6 +228,7 @@ open class IncrementalJvmCache(
constantsMap.remove(it)
inlineFunctionsMap.remove(it)
internalNameToSource.remove(it.internalName)
javaSourcesProtoMap.remove(it, changesCollector)
}
removeAllFromClassStorage(dirtyClasses.map { it.fqNameForClassNameWithoutDollars })
@@ -298,6 +324,29 @@ open class IncrementalJvmCache(
}
}
private inner class JavaSourcesProtoMap(storageFile: File) : BasicStringMap<SerializedJavaClass>(storageFile, JavaClassProtoMapValueExternalizer) {
fun process(jvmClassName: JvmClassName, newData: SerializedJavaClass, changesCollector: ChangesCollector) {
val key = jvmClassName.internalName
val oldData = storage[key]
storage[key] = newData
changesCollector.collectProtoChanges(oldData?.toProtoData(), newData.toProtoData())
}
fun remove(className: JvmClassName, changesCollector: ChangesCollector) {
val key = className.internalName
val oldValue = storage[key] ?: return
storage.remove(key)
changesCollector.collectProtoChanges(oldValue.toProtoData(), newData = null)
}
operator fun get(internalName: String) = storage[internalName]
override fun dumpValue(value: SerializedJavaClass): String =
java.lang.Long.toHexString(value.proto.toByteArray().md5())
}
// todo: reuse code with InlineFunctionsMap?
private inner class ConstantsMap(storageFile: File) : BasicStringMap<Map<String, Any>>(storageFile, ConstantsMapExternalizer) {
private fun getConstantsMap(bytes: ByteArray): Map<String, Any> {
@@ -0,0 +1,135 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.incremental
import com.intellij.psi.PsiJavaFile
import com.intellij.util.io.DataExternalizer
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.load.java.JavaClassesTracker
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
import org.jetbrains.kotlin.serialization.java.JavaClassProtoBuf
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.sure
import java.io.DataInput
import java.io.DataOutput
import java.io.File
class JavaClassesTrackerImpl(private val cache: IncrementalJvmCache) : JavaClassesTracker {
private val classToSourceSerialized: MutableMap<ClassId, SerializedJavaClassWithSource> = hashMapOf()
val javaClassesUpdates: Collection<SerializedJavaClassWithSource>
get() = classToSourceSerialized.values
private val classDescriptors: MutableList<JavaClassDescriptor> = mutableListOf()
override fun reportClass(classDescriptor: JavaClassDescriptor) {
val classId = classDescriptor.classId!!
if (!cache.isJavaClassToTrack(classId) || classDescriptor.javaSourceFile == null) return
classDescriptors.add(classDescriptor)
}
override fun onCompletedAnalysis(module: ModuleDescriptor) {
for (classId in cache.getObsoleteJavaClasses()) {
// Just force the loading obsolete classes
// We assume here that whenever an LazyJavaClassDescriptor instances is created
// it's being passed to JavaClassesTracker::reportClass
module.findClassAcrossModuleDependencies(classId)
}
for (classDescriptor in classDescriptors.toList()) {
classToSourceSerialized[classDescriptor.classId!!] =
classDescriptor.convertToProto()
}
}
}
private val JavaClassDescriptor.javaSourceFile: File?
get() = source.safeAs<PsiSourceElement>()
?.psi?.containingFile?.takeIf { it is PsiJavaFile }
?.virtualFile?.path?.let(::File)
fun JavaClassDescriptor.convertToProto(): SerializedJavaClassWithSource {
val file = javaSourceFile.sure { "convertToProto should only be called for source based classes" }
val extension = JavaClassesSerializerExtension()
val serializer = DescriptorSerializer.createTopLevel(extension)
val classProto = serializer.classProto(this).build()
val (stringTable, qualifiedNameTable) = extension.stringTable.buildProto()
return SerializedJavaClassWithSource(file, SerializedJavaClass(classProto, stringTable, qualifiedNameTable))
}
class SerializedJavaClass(
val proto: ProtoBuf.Class,
val stringTable: ProtoBuf.StringTable,
val qualifiedNameTable: ProtoBuf.QualifiedNameTable
) {
val classId: ClassId
get() = NameResolverImpl(stringTable, qualifiedNameTable).getClassId(proto.fqName)
}
data class SerializedJavaClassWithSource(
val source: File,
val proto: SerializedJavaClass
)
fun SerializedJavaClass.toProtoData() = ClassProtoData(proto, NameResolverImpl(stringTable, qualifiedNameTable))
val JAVA_CLASS_PROTOBUF_REGISTRY =
ExtensionRegistryLite.newInstance()
.also(JavaClassProtoBuf::registerAllExtensions)
// Built-ins extensions are used for annotations' serialization
.also(BuiltInsProtoBuf::registerAllExtensions)
object JavaClassProtoMapValueExternalizer : DataExternalizer<SerializedJavaClass> {
override fun save(output: DataOutput, value: SerializedJavaClass) {
output.writeBytesWithSize(value.proto.toByteArray())
output.writeBytesWithSize(value.stringTable.toByteArray())
output.writeBytesWithSize(value.qualifiedNameTable.toByteArray())
}
private fun DataOutput.writeBytesWithSize(bytes: ByteArray) {
writeInt(bytes.size)
write(bytes)
}
private fun DataInput.readBytesWithSize(): ByteArray {
val bytesLength = readInt()
return ByteArray(bytesLength).also {
readFully(it, 0, bytesLength)
}
}
override fun read(input: DataInput): SerializedJavaClass {
val proto = ProtoBuf.Class.parseFrom(input.readBytesWithSize(), JAVA_CLASS_PROTOBUF_REGISTRY)
val stringTable = ProtoBuf.StringTable.parseFrom(input.readBytesWithSize(), JAVA_CLASS_PROTOBUF_REGISTRY)
val qualifiedNameTable = ProtoBuf.QualifiedNameTable.parseFrom(input.readBytesWithSize(), JAVA_CLASS_PROTOBUF_REGISTRY)
return SerializedJavaClass(proto, stringTable, qualifiedNameTable)
}
}
@@ -79,7 +79,8 @@ fun makeCompileServices(
fun updateIncrementalCache(
generatedFiles: Iterable<GeneratedFile>,
cache: IncrementalJvmCache,
changesCollector: ChangesCollector
changesCollector: ChangesCollector,
javaChangesTracker: JavaClassesTrackerImpl?
) {
for (generatedFile in generatedFiles) {
when {
@@ -88,6 +89,11 @@ fun updateIncrementalCache(
}
}
javaChangesTracker?.javaClassesUpdates?.forEach {
(source, serializedJavaClass) ->
cache.saveJavaClassProto(source, serializedJavaClass, changesCollector)
}
cache.clearCacheForRemovedClasses(changesCollector)
}
@@ -173,7 +179,7 @@ fun mapClassesFqNamesToFiles(
for (cache in caches) {
for (dirtyClassFqName in classesFqNames) {
val srcFile = cache.getSourceFileIfClass(dirtyClassFqName)
if (srcFile == null || srcFile in excludes) continue
if (srcFile == null || srcFile in excludes || srcFile.isJavaFile()) continue
reporter.report { ("Class $dirtyClassFqName caused recompilation of: ${reporter.pathsAsString(srcFile)}") }
dirtyFiles.add(srcFile)
@@ -1,81 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.incremental
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.util.Disposer
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.PsiJavaFile
import org.jetbrains.kotlin.config.CompilerConfiguration
import java.io.File
import java.util.*
internal class ChangedJavaFilesProcessor(private val reporter: ICReporter) {
private val allSymbols = HashSet<LookupSymbol>()
private val javaLang = JavaLanguage.INSTANCE
private val psiFileFactory: PsiFileFactory by lazy {
val rootDisposable = Disposer.newDisposable()
val configuration = CompilerConfiguration()
val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val project = environment.project
PsiFileFactory.getInstance(project)
}
val allChangedSymbols: Collection<LookupSymbol>
get() = allSymbols
fun process(filesDiff: ChangedFiles.Known): ChangesEither {
val modifiedJava = filesDiff.modified.filter(File::isJavaFile)
val removedJava = filesDiff.removed.filter(File::isJavaFile)
if (removedJava.any()) {
reporter.report { "Some java files are removed: [${removedJava.joinToString()}]" }
return ChangesEither.Unknown()
}
val symbols = HashSet<LookupSymbol>()
for (javaFile in modifiedJava) {
assert(javaFile.extension.equals("java", ignoreCase = true))
val psiFile = javaFile.psiFile()
if (psiFile !is PsiJavaFile) {
reporter.report { "Expected PsiJavaFile, got ${psiFile?.javaClass}" }
return ChangesEither.Unknown()
}
psiFile.classes.forEach { it.addLookupSymbols(symbols) }
}
allSymbols.addAll(symbols)
return ChangesEither.Known(lookupSymbols = symbols)
}
private fun PsiClass.addLookupSymbols(symbols: MutableSet<LookupSymbol>) {
val fqn = qualifiedName.orEmpty()
symbols.add(LookupSymbol(name.orEmpty(), if (fqn == name) "" else fqn.removeSuffix("." + name!!)))
methods.forEach { symbols.add(LookupSymbol(it.name, fqn)) }
fields.forEach { symbols.add(LookupSymbol(it.name.orEmpty(), fqn)) }
innerClasses.forEach { it.addLookupSymbols(symbols) }
}
private fun File.psiFile(): PsiFile? =
psiFileFactory.createFileFromText(nameWithoutExtension, javaLang, readText())
}
@@ -31,8 +31,7 @@ import org.jetbrains.kotlin.incremental.multiproject.ChangesRegistry
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import java.io.File
import java.util.ArrayList
import java.util.HashSet
import java.util.*
abstract class IncrementalCompilerRunner<
Args : CommonCompilerArguments,
@@ -143,8 +142,6 @@ abstract class IncrementalCompilerRunner<
protected open fun postCompilationHook(exitCode: ExitCode) {}
protected open fun additionalDirtyFiles(caches: CacheManager, generatedFiles: List<GeneratedFile>): Iterable<File> =
emptyList()
protected open fun additionalDirtyLookupSymbols(): Iterable<LookupSymbol> =
emptyList()
protected open fun makeServices(
args: Args,
@@ -187,7 +184,7 @@ abstract class IncrementalCompilerRunner<
var exitCode = ExitCode.OK
val allGeneratedFiles = hashSetOf<GeneratedFile>()
while (dirtySources.any()) {
while (dirtySources.any() || runWithNoDirtyKotlinSources(caches)) {
caches.platformCache.markDirty(dirtySources)
caches.inputsCache.removeOutputForSourceFiles(dirtySources)
@@ -248,9 +245,6 @@ abstract class IncrementalCompilerRunner<
if (exitCode == ExitCode.OK) {
BuildInfo.write(currentBuildInfo, lastBuildInfoFile)
}
if (exitCode == ExitCode.OK && compilationMode is CompilationMode.Incremental) {
buildDirtyLookupSymbols.addAll(additionalDirtyLookupSymbols())
}
val dirtyData = DirtyData(buildDirtyLookupSymbols, buildDirtyFqNames)
processChangesAfterBuild(compilationMode, currentBuildInfo, dirtyData)
@@ -262,6 +256,8 @@ abstract class IncrementalCompilerRunner<
return exitCode
}
open fun runWithNoDirtyKotlinSources(caches: CacheManager): Boolean = false
protected open fun processChangesAfterBuild(compilationMode: CompilationMode, currentBuildInfo: BuildInfo, dirtyData: DirtyData) {
if (changesRegistry == null) return
@@ -283,4 +279,4 @@ abstract class IncrementalCompilerRunner<
override fun checkCanceled() {
}
}
}
}
@@ -31,14 +31,12 @@ import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.multiproject.ArtifactChangesProvider
import org.jetbrains.kotlin.incremental.multiproject.ChangesRegistry
import org.jetbrains.kotlin.load.java.JavaClassesTracker
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import java.io.File
import java.util.*
import kotlin.collections.HashSet
fun makeIncrementally(
cachesDir: File,
@@ -110,8 +108,6 @@ class IncrementalJvmCompilerRunner(
override fun destinationDir(args: K2JVMCompilerArguments): File =
args.destinationAsFile
private var javaFilesProcessor = ChangedJavaFilesProcessor(reporter)
override fun calculateSourcesToCompile(caches: IncrementalJvmCachesManager, changedFiles: ChangedFiles.Known, args: K2JVMCompilerArguments): CompilationMode {
val dirtyFiles = getDirtyFiles(changedFiles)
@@ -170,23 +166,22 @@ class IncrementalJvmCompilerRunner(
return CompilationMode.Rebuild { "could not get changes from modified classpath entries: ${reporter.pathsAsString(modifiedClasspathEntries)}" }
}
val javaFilesChanges = javaFilesProcessor.process(changedFiles)
val affectedJavaSymbols = when (javaFilesChanges) {
is ChangesEither.Known -> javaFilesChanges.lookupSymbols
is ChangesEither.Unknown -> return CompilationMode.Rebuild { "Could not get changes for java files" }
}
processChangedJava(changedFiles, caches)
if ((changedFiles.modified + changedFiles.removed).any { it.extension.toLowerCase() == "xml" }) {
return CompilationMode.Rebuild { "XML resource files were changed" }
}
markDirtyBy(affectedJavaSymbols)
markDirtyBy(classpathChanges.lookupSymbols)
markDirtyBy(classpathChanges.fqNames)
return CompilationMode.Incremental(dirtyFiles)
}
private fun processChangedJava(changedFiles: ChangedFiles.Known, caches: IncrementalJvmCachesManager) {
caches.platformCache.markDirty((changedFiles.modified + changedFiles.removed).filter(File::isJavaFile))
}
private fun getClasspathChanges(
modifiedClasspath: List<File>,
lastBuildInfo: BuildInfo?
@@ -249,9 +244,15 @@ class IncrementalJvmCompilerRunner(
generatedFiles: List<GeneratedFile>,
changesCollector: ChangesCollector
) {
updateIncrementalCache(generatedFiles, caches.platformCache, changesCollector)
updateIncrementalCache(
generatedFiles, caches.platformCache, changesCollector,
services[JavaClassesTracker::class.java] as? JavaClassesTrackerImpl
)
}
override fun runWithNoDirtyKotlinSources(caches: IncrementalJvmCachesManager): Boolean =
caches.platformCache.getObsoleteJavaClasses().isNotEmpty()
override fun additionalDirtyFiles(
caches: IncrementalJvmCachesManager,
generatedFiles: List<GeneratedFile>
@@ -292,9 +293,6 @@ class IncrementalJvmCompilerRunner(
return result
}
override fun additionalDirtyLookupSymbols(): Iterable<LookupSymbol> =
javaFilesProcessor.allChangedSymbols
override fun processChangesAfterBuild(compilationMode: CompilationMode, currentBuildInfo: BuildInfo, dirtyData: DirtyData) {
super.processChangesAfterBuild(compilationMode, currentBuildInfo, dirtyData)
@@ -323,6 +321,8 @@ class IncrementalJvmCompilerRunner(
val targetToCache = mapOf(targetId to caches.platformCache)
val incrementalComponents = IncrementalCompilationComponentsImpl(targetToCache)
register(IncrementalCompilationComponents::class.java, incrementalComponents)
val changesTracker = JavaClassesTrackerImpl(caches.platformCache)
register(JavaClassesTracker::class.java, changesTracker)
}
override fun runCompiler(
@@ -1108,18 +1108,42 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/withJava/javaUsedInKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
}
@TestMetadata("changeFieldType")
public void testChangeFieldType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeFieldType/");
doTest(fileName);
}
@TestMetadata("changeNotUsedSignature")
public void testChangeNotUsedSignature() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeNotUsedSignature/");
doTest(fileName);
}
@TestMetadata("changePropertyOverrideType")
public void testChangePropertyOverrideType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changePropertyOverrideType/");
doTest(fileName);
}
@TestMetadata("changeSignature")
public void testChangeSignature() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeSignature/");
doTest(fileName);
}
@TestMetadata("changeSignaturePackagePrivate")
public void testChangeSignaturePackagePrivate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeSignaturePackagePrivate/");
doTest(fileName);
}
@TestMetadata("changeSignatureStatic")
public void testChangeSignatureStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeSignatureStatic/");
doTest(fileName);
}
@TestMetadata("constantChanged")
public void testConstantChanged() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/constantChanged/");
@@ -1180,6 +1204,12 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
doTest(fileName);
}
@TestMetadata("mixedInheritance")
public void testMixedInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/mixedInheritance/");
doTest(fileName);
}
@TestMetadata("notChangeSignature")
public void testNotChangeSignature() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/notChangeSignature/");
@@ -1472,4 +1502,31 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
}
}
}
@TestMetadata("jps-plugin/testData/incremental/incrementalJvmCompilerOnly")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class IncrementalJvmCompilerOnly extends AbstractIncrementalJvmCompilerRunnerTest {
@TestMetadata("addAnnotationToJavaClass")
public void testAddAnnotationToJavaClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/incrementalJvmCompilerOnly/addAnnotationToJavaClass/");
doTest(fileName);
}
@TestMetadata("addNestedClass")
public void testAddNestedClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/incrementalJvmCompilerOnly/addNestedClass/");
doTest(fileName);
}
public void testAllFilesPresentInIncrementalJvmCompilerOnly() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/incrementalJvmCompilerOnly"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
}
@TestMetadata("changeAnnotationInJavaClass")
public void testChangeAnnotationInJavaClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/incrementalJvmCompilerOnly/changeAnnotationInJavaClass/");
doTest(fileName);
}
}
}
@@ -24,7 +24,7 @@ class Services private constructor(private val map: Map<Class<*>, Any>) {
val EMPTY: Services = Builder().build()
}
fun <T> get(interfaceClass: Class<T>): T? {
operator fun <T> get(interfaceClass: Class<T>): T? {
@Suppress("UNCHECKED_CAST")
return map[interfaceClass] as T?
}
@@ -913,6 +913,7 @@ fun main(args: Array<String>) {
model("incremental/classHierarchyAffected", extension = null, recursive = false)
model("incremental/inlineFunCallSite", extension = null, excludeParentDirs = true)
model("incremental/withJava", extension = null, excludeParentDirs = true)
model("incremental/incrementalJvmCompilerOnly", extension = null, excludeParentDirs = true)
}
testClass<AbstractIncrementalJsCompilerRunnerTest> {
@@ -949,18 +949,42 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/withJava/javaUsedInKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
}
@TestMetadata("changeFieldType")
public void testChangeFieldType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeFieldType/");
doTest(fileName);
}
@TestMetadata("changeNotUsedSignature")
public void testChangeNotUsedSignature() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeNotUsedSignature/");
doTest(fileName);
}
@TestMetadata("changePropertyOverrideType")
public void testChangePropertyOverrideType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changePropertyOverrideType/");
doTest(fileName);
}
@TestMetadata("changeSignature")
public void testChangeSignature() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeSignature/");
doTest(fileName);
}
@TestMetadata("changeSignaturePackagePrivate")
public void testChangeSignaturePackagePrivate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeSignaturePackagePrivate/");
doTest(fileName);
}
@TestMetadata("changeSignatureStatic")
public void testChangeSignatureStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/changeSignatureStatic/");
doTest(fileName);
}
@TestMetadata("constantChanged")
public void testConstantChanged() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/constantChanged/");
@@ -1021,6 +1045,12 @@ public class IncrementalJpsTestGenerated extends AbstractIncrementalJpsTest {
doTest(fileName);
}
@TestMetadata("mixedInheritance")
public void testMixedInheritance() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/mixedInheritance/");
doTest(fileName);
}
@TestMetadata("notChangeSignature")
public void testNotChangeSignature() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("jps-plugin/testData/incremental/withJava/javaUsedInKotlin/notChangeSignature/");
@@ -333,7 +333,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
val changesCollector = ChangesCollector()
for ((target, files) in generatedFiles) {
updateIncrementalCache(files, incrementalCaches[target]!!, changesCollector)
updateIncrementalCache(files, incrementalCaches[target]!!, changesCollector, null)
}
updateLookupStorage(chunk, lookupTracker, dataManager, dirtyFilesHolder, filesToCompile)
@@ -0,0 +1,2 @@
public @interface Ann {
}
@@ -0,0 +1,3 @@
public class JavaClass {
public String foo() { return null; }
}
@@ -0,0 +1,4 @@
@Ann
public class JavaClass {
public String foo() { return null; }
}
@@ -0,0 +1,20 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: ABORT
------------------------------------------
SUCCESS
@@ -0,0 +1,3 @@
fun foo() {
}
@@ -0,0 +1,3 @@
fun bar() {
JavaClass().foo()
}
@@ -0,0 +1,3 @@
public class JavaClass {
public String foo() { return null; }
}
@@ -0,0 +1,5 @@
public class JavaClass {
public String foo() { return null; }
public static class Nested {
}
}
@@ -0,0 +1,21 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: ABORT
------------------------------------------
COMPILATION FAILED
Unresolved reference: Nested
@@ -0,0 +1,5 @@
import test.*
fun foo(x: Nested) {
JavaClass().foo()
}
@@ -0,0 +1,3 @@
package test
class Nested
@@ -0,0 +1,6 @@
import test.*
import JavaClass.*
fun bar(x: Nested) {
JavaClass().foo()
}
@@ -0,0 +1,3 @@
public @interface Ann {
String value() default "1";
}
@@ -0,0 +1,4 @@
@Ann
public class JavaClass {
public String foo() { return null; }
}
@@ -0,0 +1,4 @@
@Ann("")
public class JavaClass {
public String foo() { return null; }
}
@@ -0,0 +1,20 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: ABORT
------------------------------------------
SUCCESS
@@ -0,0 +1,3 @@
fun foo() {
}
@@ -0,0 +1,3 @@
fun bar() {
JavaClass().foo()
}
@@ -1,14 +0,0 @@
================ Step #1 =================
Compiling files:
src/TheClass.kt
src/other.kt
End of files
Exit code: OK
------------------------------------------
================ Step #2 =================
Compiling files:
End of files
Exit code: OK
------------------------------------------
@@ -0,0 +1,4 @@
public class JavaClass {
public String stringField;
public int intField;
}
@@ -0,0 +1,4 @@
public class JavaClass {
public CharSequence stringField;
public int intField;
}
@@ -0,0 +1,19 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: OK
------------------------------------------
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().intField
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().stringField
}
@@ -0,0 +1,4 @@
public class JavaClass implements KotlinInterface {
public CharSequence getX() { return ""; }
public int getY() { return 1; }
}
@@ -0,0 +1,4 @@
public class JavaClass implements KotlinInterface {
public String getX() { return ""; }
public int getY() { return 1; }
}
@@ -0,0 +1,4 @@
interface KotlinInterface {
val x: CharSequence
val y: Int
}
@@ -0,0 +1,19 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: OK
------------------------------------------
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().y
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().x
}
@@ -1,4 +1,7 @@
public class JavaClass {
public static void foo() {
public void foo() {
}
public void bar() {
}
}
@@ -1,5 +1,8 @@
public class JavaClass {
public static String foo() {
return ":)";
public String foo() {
return "";
}
public void bar() {
}
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().bar()
}
@@ -1,3 +1,3 @@
fun main(args: Array<String>) {
JavaClass.foo()
JavaClass().foo()
}
@@ -0,0 +1,7 @@
public class JavaClass {
public void foo() {
}
public void bar() {
}
}
@@ -0,0 +1,7 @@
public class JavaClass {
void foo() {
}
public void bar() {
}
}
@@ -0,0 +1,19 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: OK
------------------------------------------
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().bar()
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass().foo()
}
@@ -0,0 +1,7 @@
public class JavaClass {
public static void foo() {
}
public static void bar() {
}
}
@@ -0,0 +1,8 @@
public class JavaClass {
public static String foo() {
return "";
}
public static void bar() {
}
}
@@ -0,0 +1,19 @@
================ Step #1 =================
Cleaning output files:
out/production/module/JavaClass.class
End of files
Exit code: NOTHING_DONE
------------------------------------------
Compiling files:
src/JavaClass.java
End of files
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/UsageKt.class
End of files
Compiling files:
src/usage.kt
End of files
Exit code: OK
------------------------------------------
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass.bar()
}
@@ -0,0 +1,3 @@
fun main(args: Array<String>) {
JavaClass.foo()
}
@@ -1,7 +0,0 @@
================ Step #1 =================
Compiling files:
src/JavaClass.java
src/usage.kt
End of files
Exit code: OK
@@ -0,0 +1,3 @@
open class BaseClass {
fun foo() {}
}
@@ -0,0 +1,3 @@
open class BaseClass {
fun foo(): String = "OK"
}
@@ -0,0 +1,2 @@
public class DerivedClass1 extends BaseClass {
}
@@ -0,0 +1,2 @@
class DerivedClass2 : DerivedClass1() {
}
@@ -0,0 +1,33 @@
================ Step #1 =================
Cleaning output files:
out/production/module/BaseClass.class
End of files
Compiling files:
src/BaseClass.kt
End of files
Marked as dirty by Kotlin:
src/usage1.kt
src/usage2.kt
src/usage3.kt
Exit code: ADDITIONAL_PASS_REQUIRED
------------------------------------------
Cleaning output files:
out/production/module/DerivedClass1.class
out/production/module/DerivedClass2.class
out/production/module/META-INF/module.kotlin_module
out/production/module/Usage1Kt.class
out/production/module/Usage2Kt.class
out/production/module/Usage3Kt.class
End of files
Compiling files:
src/DerivedClass2.kt
src/usage1.kt
src/usage2.kt
src/usage3.kt
End of files
Exit code: OK
------------------------------------------
Compiling files:
src/DerivedClass1.java
End of files
@@ -0,0 +1,3 @@
fun main4() {
DerivedClass2().hashCode()
}
@@ -0,0 +1,3 @@
fun main1() {
BaseClass().foo()
}
@@ -0,0 +1,3 @@
fun main2() {
DerivedClass1().foo()
}
@@ -0,0 +1,3 @@
fun main3() {
DerivedClass2().foo()
}
@@ -1,6 +0,0 @@
================ Step #1 =================
Compiling files:
src/JavaClass.java
src/usage.kt
End of files