From c7e5beece524f0a9610b4270d06a5ddc447b9dc7 Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Thu, 26 Nov 2020 21:17:59 +0000 Subject: [PATCH] Use types are origins for incremental KAPT and track generated source This change introduces tracking of generated sources structure in order to e.g track classpath changes impacting generated sources. This fixes KT-42182. Also, origin tracking for isolating processors is now using types, allowing for origin elements from classpath. This fixes KT-34340. However, classpath origin is used only to invalidate generated files when the type changes and processing will not be requested for that type. This is in line with the incap spec. --- ...rementalProcessorReferencingClasspath.java | 58 +++++++ .../KaptIncrementalWithAggregatingApt.kt | 46 ++++-- .../gradle/KaptIncrementalWithIsolatingApt.kt | 57 +++++++ .../kotlin/kapt3/base/KaptContext.kt | 10 +- .../kotlin/kapt3/base/annotationProcessing.kt | 18 +- .../base/incremental/IncrementalAptCache.kt | 124 +++++++++----- .../kotlin/kapt3/base/incremental/cache.kt | 121 ++++++++++---- .../base/incremental/classStructureCache.kt | 154 ++++++++---------- .../base/incremental/incrementalProcessors.kt | 65 ++++---- .../kapt3/base/incremental/javacVisitors.kt | 24 --- .../DynamicIncrementalProcessorTest.kt | 4 +- .../IsolatingIncrementalProcessorTest.kt | 26 +-- .../incremental/JavaClassCacheManagerTest.kt | 36 +--- .../TestSimpleIncrementalAptCache.kt | 6 +- 14 files changed, 475 insertions(+), 274 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/org/jetbrains/kotlin/gradle/incapt/IncrementalProcessorReferencingClasspath.java diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/org/jetbrains/kotlin/gradle/incapt/IncrementalProcessorReferencingClasspath.java b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/org/jetbrains/kotlin/gradle/incapt/IncrementalProcessorReferencingClasspath.java new file mode 100644 index 00000000000..4532035db46 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/java/org/jetbrains/kotlin/gradle/incapt/IncrementalProcessorReferencingClasspath.java @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.incapt; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import java.io.IOException; +import java.io.Writer; +import java.util.Collections; +import java.util.Set; + +/** Simple processor that generates a class for every annotated element (class, field, method). */ +public class IncrementalProcessorReferencingClasspath extends AbstractProcessor { + + // Type that all generated sources will extend. + public static final String CLASSPATH_TYPE = "com.example.FromClasspath"; + + @Override + public Set getSupportedAnnotationTypes() { + return Collections.singleton("example.ExampleAnnotation"); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (annotations.isEmpty()) return true; + + for (Element element : roundEnv.getElementsAnnotatedWith(annotations.iterator().next())) { + if (element instanceof TypeElement || element instanceof ExecutableElement || element instanceof VariableElement) { + String name = element.getSimpleName().toString(); + name = name.substring(0, 1).toUpperCase() + name.substring(1) + "Generated"; + + String packageName; + if (element instanceof TypeElement) { + packageName = element.getEnclosingElement().getSimpleName().toString(); + } + else { + packageName = element.getEnclosingElement().getEnclosingElement().getSimpleName().toString(); + } + + try (Writer writer = processingEnv.getFiler().createSourceFile(packageName + "." + name, element).openWriter()) { + writer.append("package ").append(packageName).append(";"); + writer.append("\npublic class ").append(name).append(" extends ").append(CLASSPATH_TYPE).append(" {}"); + } + catch (IOException ignored) { + } + } + } + + return false; + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt index e7e629f65e9..156d4ac1650 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithAggregatingApt.kt @@ -27,6 +27,7 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { override fun defaultBuildOptions(): BuildOptions = super.defaultBuildOptions().copy( incremental = true, + debug=false, kaptOptions = KaptOptions( verbose = true, useWorkers = true, @@ -171,7 +172,7 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { } project.build("build") { assertSuccessful() - assertTrue(getProcessedSources(output).isEmpty()) + assertTrue(output.contains("Skipping annotation processing as all sources are up-to-date.")) } } @@ -275,8 +276,9 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { assertEquals( setOf( fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/NoAnnotationsKt.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ), getProcessedSources(output) + fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath, + fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary }, + ).filterNotNull().toSet(), getProcessedSources(output) ) checkAggregatingResource { lines -> @@ -302,9 +304,9 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { assertEquals( setOf( fileInWorkingDir("build/tmp/kapt3/stubs/main/baz/BazClass.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ), - getProcessedSources(output) + fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath, + fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary }, + ).filterNotNull().toSet(), getProcessedSources(output) ) checkAggregatingResource { lines -> @@ -330,9 +332,9 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { assertEquals( setOf( fileInWorkingDir("build/tmp/kapt3/stubs/main/baz/BazClass.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ), - getProcessedSources(output) + fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath, + fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary }, + ).filterNotNull().toSet(), getProcessedSources(output) ) checkAggregatingResource { lines -> @@ -351,8 +353,30 @@ class KaptIncrementalWithAggregatingApt : KaptIncrementalIT() { assertEquals( setOf( fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/NoAnnotationsKt.java").canonicalPath, - fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath - ), getProcessedSources(output) + fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath, + fileInWorkingDir("build/generated/source/kapt/main/bar/WithAnnotationGenerated.java").canonicalPath.takeUnless { isBinary }, + fileInWorkingDir("build/generated/source/kapt/main/BazClass/BazNestedGenerated.java").canonicalPath.takeUnless { isBinary }, + ).filterNotNull().toSet(), getProcessedSources(output) + ) + + checkAggregatingResource { lines -> + assertEquals(2, lines.size) + assertTrue(lines.contains("WithAnnotationGenerated")) + assertTrue(lines.contains("BazNestedGenerated")) + } + } + + // make sure that changing the origin of isolating that produced + project.projectFile("withAnnotation.kt").modify { current -> current.substringBeforeLast("}") + "\nfun otherFunction() {} }" } + project.build("build", options = buildOptions) { + assertSuccessful() + + assertEquals( + setOf( + fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/WithAnnotation.java").canonicalPath, + fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath, + fileInWorkingDir("build/generated/source/kapt/main/BazClass/BazNestedGenerated.java").canonicalPath.takeUnless { isBinary }, + ).filterNotNull().toSet(), getProcessedSources(output) ) checkAggregatingResource { lines -> diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt index 30a7a13dbc2..4ef3d4bd631 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt @@ -6,10 +6,14 @@ package org.jetbrains.kotlin.gradle import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessor +import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessorReferencingClasspath import org.jetbrains.kotlin.gradle.util.modify import org.junit.Assert.assertEquals import org.junit.Assume import org.junit.Test +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.Opcodes +import org.objectweb.asm.Type import test.kt33617.MyClass import java.io.File import java.util.zip.ZipEntry @@ -192,6 +196,59 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { assertSuccessful() } } + + /** Regression test for https://youtrack.jetbrains.com/issue/KT-42182. */ + @Test + fun testGeneratedSourcesImpactedByClasspathChanges() { + val project = Project( + "kaptIncrementalCompilationProject", + GradleVersionRequired.None + ).apply { + setupIncrementalAptProject("ISOLATING", procClass = IncrementalProcessorReferencingClasspath::class.java) + } + project.gradleSettingsScript().writeText("include ':', ':lib'") + val classpathTypeSource = project.projectDir.resolve("lib").run { + mkdirs() + resolve("build.gradle").writeText("apply plugin: 'java'") + val source = resolve("src/main/java/" + IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.replace(".", "/") + ".java") + source.parentFile.mkdirs() + + source.writeText( + """ + package ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringBeforeLast(".")}; + public class ${IncrementalProcessorReferencingClasspath.CLASSPATH_TYPE.substringAfterLast(".")} {} + """.trimIndent() + ) + return@run source + } + project.gradleBuildScript().appendText( + """ + + dependencies { + implementation project(':lib') + } + """.trimIndent() + ) + project.build("clean", "kaptKotlin") { + assertSuccessful() + } + + // change type that all generated sources reference + classpathTypeSource.writeText(classpathTypeSource.readText().replace("}", "int i = 10;\n}")) + project.build("build") { + assertSuccessful() + assertEquals( + setOf( + fileInWorkingDir("build/tmp/kapt3/stubs/main/foo/A.java").canonicalPath, + fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/B.java").canonicalPath, + fileInWorkingDir("build/tmp/kapt3/stubs/main/bar/UseBKt.java").canonicalPath, + fileInWorkingDir("build/tmp/kapt3/stubs/main/baz/UtilKt.java").canonicalPath, + fileInWorkingDir("build/tmp/kapt3/stubs/main/error/NonExistentClass.java").canonicalPath + ), + getProcessedSources(output) + ) + } + } } private const val patternApt = "Processing java sources with annotation processors:" diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt index 5f06b01a622..5b8af760d28 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/KaptContext.kt @@ -60,10 +60,16 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge JavaClassCacheManager(it) } if (options.flags[KaptFlag.INCREMENTAL_APT]) { - sourcesToReprocess = + sourcesToReprocess = run { + val start = System.currentTimeMillis() cacheManager?.invalidateAndGetDirtyFiles( options.changedFiles, options.classpathChanges - ) ?: SourcesToReprocess.FullRebuild + ).also { + if (logger.isVerbose) { + logger.info("Computing sources to reprocess took ${System.currentTimeMillis() - start}[ms].") + } + } + }?: SourcesToReprocess.FullRebuild if (sourcesToReprocess == SourcesToReprocess.FullRebuild) { // remove all generated sources and classes diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt index 1919bb94ca1..3ce96ff3de6 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/annotationProcessing.kt @@ -14,6 +14,7 @@ import com.sun.tools.javac.processing.JavacProcessingEnvironment import com.sun.tools.javac.tree.JCTree import org.jetbrains.kotlin.base.kapt3.KaptFlag import org.jetbrains.kotlin.kapt3.base.incremental.* +import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaCompiler import org.jetbrains.kotlin.kapt3.base.util.KaptBaseError import org.jetbrains.kotlin.kapt3.base.util.KaptLogger import org.jetbrains.kotlin.kapt3.base.util.isJava9OrLater @@ -40,6 +41,13 @@ fun KaptContext.doAnnotationProcessing( val compilerAfterAP: JavaCompiler try { + if (javaSourceFiles.isEmpty() && aggregatedTypes.isEmpty() && additionalSources.isEmpty()) { + if (logger.isVerbose) { + logger.info("Skipping annotation processing as all sources are up-to-date.") + } + return + } + if (isJava9OrLater()) { val initProcessAnnotationsMethod = JavaCompiler::class.java.declaredMethods.single { it.name == "initProcessAnnotations" } initProcessAnnotationsMethod.invoke(compiler, wrappedProcessors, emptyList(), emptyList()) @@ -66,11 +74,6 @@ fun KaptContext.doAnnotationProcessing( CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources) ) - val generatedSourcesListener = sourcesStructureListener?.let { - compiler.getTaskListeners().remove(it) - GeneratedTypesTaskListener(cacheManager!!.javaCache) - }?.also { compiler.getTaskListeners().add(it) } - val additionalClassNames = JavacList.from(aggregatedTypes) if (isJava9OrLater()) { val processAnnotationsMethod = @@ -78,13 +81,12 @@ fun KaptContext.doAnnotationProcessing( processAnnotationsMethod.invoke(compiler, analyzedFiles, additionalClassNames) compiler } else { - compiler.processAnnotations(analyzedFiles, additionalClassNames).also { - generatedSourcesListener?.let { compiler.getTaskListeners().remove(it) } - } + compiler.processAnnotations(analyzedFiles, additionalClassNames) } } catch (e: AnnotationProcessingError) { throw KaptBaseError(KaptBaseError.Kind.EXCEPTION, e.cause ?: e) } + sourcesStructureListener?.let { compiler.getTaskListeners().remove(it) } cacheManager?.updateCache(processors, sourcesStructureListener?.failureReason != null) diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/IncrementalAptCache.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/IncrementalAptCache.kt index be6f5fc7249..bb3697dc4b0 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/IncrementalAptCache.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/IncrementalAptCache.kt @@ -10,16 +10,19 @@ import java.io.Serializable class IncrementalAptCache : Serializable { - private val aggregatingGenerated: MutableMap = mutableMapOf() + private val aggregatingGenerated: MutableSet = mutableSetOf() private val aggregatedTypes: MutableSet = linkedSetOf() - private val isolatingMapping: MutableMap> = mutableMapOf() - // Annotations claimed by aggregating annotation processors - private val aggregatingClaimedAnnotations: MutableSet = mutableSetOf() + private val isolatingMapping: MutableMap = mutableMapOf() var isIncremental = true private set - fun updateCache(processors: List): Boolean { + fun updateCache(processors: List, failedToAnalyzeSources: Boolean): Boolean { + if (failedToAnalyzeSources) { + invalidateCache() + return false + } + val aggregating = mutableListOf() val isolating = mutableListOf() val nonIncremental = mutableListOf() @@ -38,60 +41,68 @@ class IncrementalAptCache : Serializable { aggregatingGenerated.clear() aggregating.forEach { - it.getGeneratedToSourcesAll().mapValuesTo(aggregatingGenerated) { (_, value) -> - value?.first - } + aggregatingGenerated.addAll(it.getGeneratedToSources().keys) } - aggregatingClaimedAnnotations.clear() - aggregatingClaimedAnnotations.addAll(aggregating.flatMap { it.supportedAnnotationTypes }) - aggregatedTypes.clear() aggregatedTypes.addAll(aggregating.flatMap { it.getAggregatedTypes() }) - for (isolatingProcessor in isolating) { - isolatingProcessor.getGeneratedToSourcesAll().forEach { - isolatingMapping[it.key] = it.value!!.first to it.value!!.second!! + isolating.forEach { + it.getGeneratedToSources().forEach { (file, type) -> + isolatingMapping[file] = type!! } } + return true } - fun getAggregatingClaimedAnnotations(): Set = aggregatingClaimedAnnotations - - /** Returns generated Java sources originating from aggregating APs. */ - fun invalidateAggregating(): Pair, List> { - val dirtyAggregating = aggregatingGenerated.keys.filter { it.isJavaFileOrClass() } - aggregatingGenerated.forEach { it.key.delete() } + /** + * Invalidates all data collected about aggregating APs, making the cache ready for the next round of data collection. Also, + * all files generated by aggregating APs are deleted. + */ + fun invalidateAggregating() { + aggregatingGenerated.forEach { it.delete() } aggregatingGenerated.clear() - - val dirtyAggregated = ArrayList(aggregatedTypes) aggregatedTypes.clear() - - return dirtyAggregating to dirtyAggregated } - /** Returns generated Java sources originating from the specified sources, and generated by isloating APs. */ - fun invalidateIsolatingGenerated(fromSources: Set): Pair, Set> { - val allInvalidated = mutableListOf() - val invalidatedClassIds = mutableSetOf() - var changedSources = fromSources.toSet() + /** + * Prepares isolating processors for incremental compilation. The specified generated files are removed, and mapping + * information is deleted for them. The invalidation is non-transitive. + */ + fun invalidateIsolatingForOriginTypes(originatingTypes: Set) { + val isolatingGenerated = mutableSetOf() + isolatingMapping.forEach { (file, type) -> + if (type in originatingTypes) { + isolatingGenerated.add(file) + } + } + + isolatingGenerated.forEach { + isolatingMapping.remove(it) + it.delete() + } + } + + fun getIsolatingGeneratedTypesForOrigins( + originatingTypes: Set, + typeInfoProvider: (Collection) -> Set + ): List { + val allGeneratedTypes = mutableListOf() + var currentOrigins = originatingTypes.toSet() // We need to do it in a loop because mapping could be: [AGenerated.java -> A.java, AGeneratedGenerated.java -> AGenerated.java] - while (changedSources.isNotEmpty()) { - val generated = isolatingMapping.filter { changedSources.contains(it.value.second) }.keys - generated.forEach { - if (it.isJavaFileOrClass()) { - allInvalidated.add(it) - isolatingMapping[it]?.first?.let { invalidatedClassIds.add(it) } + while (currentOrigins.isNotEmpty()) { + val generated = mutableSetOf() + isolatingMapping.forEach { (file, origin) -> + if (origin in currentOrigins) { + generated.add(file) } - - it.delete() - isolatingMapping.remove(it) } - changedSources = generated + currentOrigins = typeInfoProvider(generated) + allGeneratedTypes.addAll(currentOrigins) } - return allInvalidated to invalidatedClassIds + return allGeneratedTypes } private fun File.isJavaFileOrClass() = extension == "java" || extension == "class" @@ -100,5 +111,38 @@ class IncrementalAptCache : Serializable { isIncremental = false aggregatingGenerated.clear() isolatingMapping.clear() + aggregatedTypes.clear() + } + + /** Gets the originating type for the specified type generated by isolating AP. */ + fun getOriginForGeneratedIsolatingType(generatedType: String, sourceFileProvider: (String) -> File?): String { + val generatedFile = checkNotNull(sourceFileProvider(generatedType)) { "Unable to find source for $generatedType" } + return isolatingMapping.getValue(generatedFile) + } + + /** Returns types that were processed by aggregating APs. */ + fun getAggregatingOrigins(): Set = aggregatedTypes + + /** Returns all types generated by aggregating APs. */ + fun getAggregatingGeneratedTypes(typeInfoProvider: (Collection) -> Set): Set { + val generatedAggregating: MutableSet = HashSet(aggregatingGenerated.size) + aggregatingGenerated.forEach { + if (it.isJavaFileOrClass()) { + generatedAggregating.add(it) + } + } + return typeInfoProvider(generatedAggregating) + } + + /** Returns all types generated by isolating APs. */ + fun getIsolatingGeneratedTypes(typeInfoProvider: (Collection) -> Set): Set { + val generatedIsolating: MutableSet = HashSet(isolatingMapping.size) + + isolatingMapping.keys.forEach { + if (it.isJavaFileOrClass()) { + generatedIsolating.add(it) + } + } + return typeInfoProvider(generatedIsolating) } } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt index 25f615725ba..a6f8936cfb8 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/cache.kt @@ -19,8 +19,18 @@ class JavaClassCacheManager(val file: File) : Closeable { private var closed = false fun updateCache(processors: List, failedToAnalyzeSources: Boolean) { - if (failedToAnalyzeSources || !aptCache.updateCache(processors)) { + if (!aptCache.updateCache(processors, failedToAnalyzeSources)) { javaCache.invalidateAll() + return + } + // Compilation is fully incremental, record types defined in generated .class files + processors.forEach { processor -> + processor.getGeneratedClassFilesToTypes().forEach { (classFile, type) -> + val typeInformation = SourceFileStructure(classFile.toURI()).also { + it.addDeclaredType(type) + } + javaCache.addSourceStructure(typeInformation) + } } } @@ -39,38 +49,93 @@ class JavaClassCacheManager(val file: File) : Closeable { } val changes = Changes(changedSources, dirtyClasspathFqNames.toSet()) - val filesToReprocess = javaCache.invalidateEntriesForChangedFiles(changes) + val aggregatingGeneratedTypes = aptCache.getAggregatingGeneratedTypes(javaCache::getTypesForFiles) + val impactedTypes = getAllImpactedTypes(changes, aggregatingGeneratedTypes) + val isolatingGeneratedTypes = aptCache.getIsolatingGeneratedTypes(javaCache::getTypesForFiles) - return when (filesToReprocess) { - is SourcesToReprocess.FullRebuild -> SourcesToReprocess.FullRebuild - is SourcesToReprocess.Incremental -> { - val toReprocess = filesToReprocess.toReprocess.toMutableSet() + val sourcesToReprocess = changedSources.toMutableSet() + val classNamesToReprocess = mutableListOf() + var shouldProcessAggregating = false - val (invalidatedIsolatingGenerated, invalidatedIsolatingId) = aptCache.invalidateIsolatingGenerated(toReprocess) - val generatedDirtyTypes = javaCache.invalidateGeneratedTypes(invalidatedIsolatingGenerated).toMutableSet() /*+*/ - - val aggregatedTypes = mutableListOf() - if (!toReprocess.isEmpty()) { - // only if there are some files to reprocess we should invalidate the aggregating ones - val (aggregatingGenerated, aggregatedTypes1) = aptCache.invalidateAggregating() - aggregatedTypes.addAll(aggregatedTypes1) - generatedDirtyTypes.addAll(javaCache.invalidateGeneratedTypes(aggregatingGenerated)) - - toReprocess.addAll( - javaCache.invalidateEntriesAnnotatedWith(aptCache.getAggregatingClaimedAnnotations()) - ) + for (impactedType in impactedTypes) { + if (impactedType !in isolatingGeneratedTypes && impactedType !in aggregatingGeneratedTypes) { + // Reprocess only if original source + javaCache.getSourceForType(impactedType)?.let { + sourcesToReprocess.add(it) } - - SourcesToReprocess.Incremental( - toReprocess.toList(), - generatedDirtyTypes, - aggregatedTypes.also { - it.removeAll(filesToReprocess.dirtyTypes) - it.removeAll(generatedDirtyTypes) - it.removeAll(invalidatedIsolatingId) - }) + } else if (impactedType in isolatingGeneratedTypes) { + // this is a generated type by isolating AP + val isolatingOrigin = aptCache.getOriginForGeneratedIsolatingType(impactedType, javaCache::getSourceForType) + if (isolatingOrigin in impactedTypes) { + // we'll process origin, no need to do it now + continue + } + val originSource = javaCache.getSourceForType(isolatingOrigin) + if (originSource?.extension == "java") { + sourcesToReprocess.add(originSource) + } else if (originSource?.extension == "class") { + // This is a generated .class file that we need to reprocess. + classNamesToReprocess.add(isolatingOrigin) + } else { + // This is a type from classpath that was used as origin, just ignore it. It is used just to remove the generated file. + } + } else { + // processed separately + shouldProcessAggregating = true } } + + if (shouldProcessAggregating || sourcesToReprocess.isNotEmpty() || classNamesToReprocess.isNotEmpty()) { + for (aggregatingOrigin in aptCache.getAggregatingOrigins()) { + if (aggregatingOrigin in impactedTypes) continue + + val originSource = javaCache.getSourceForType(aggregatingOrigin) + if (originSource?.extension == "java") { + sourcesToReprocess.add(originSource) + } else if (originSource?.extension == "class") { + // This is a generated .class file that we need to reprocess. + classNamesToReprocess.add(aggregatingOrigin) + } + } + + // Invalidate state only if there are some files that will be reprocessed + javaCache.invalidateDataForTypes(impactedTypes) + aptCache.invalidateAggregating() + // for isolating, invalidate both own types and classpath types + aptCache.invalidateIsolatingForOriginTypes(impactedTypes) + aptCache.invalidateIsolatingForOriginTypes(dirtyClasspathFqNames) + } + + return SourcesToReprocess.Incremental(sourcesToReprocess.toList(), impactedTypes, classNamesToReprocess) + } + + private fun getAllImpactedTypes(changes: Changes, aggregatingGeneratedTypes: Set): MutableSet { + val impactedTypes = javaCache.getAllImpactedTypes(changes) + + /** + * In order to find all impacted types we do the following: + * - impacted types is a set of types that have changed from the previous compilation + * - if there is a changed source or a source file that is impacted by type changes, we'll need to run aggregating APs, so we + * invalidate all aggregating generated types, and add them to set of impacted types. + * - using this new impacted types set, we find all types generated by isolating APs with origins in those types + * - if there are some generated types by isolating APs, we'll need to run aggregating APs, so we invalidate all aggregating types + * and add them to impacted types. + * - using the final value of impacted types we get all generated types by isolating APs and add them to impacted types + */ + if (changes.sourceChanges.isNotEmpty() || impactedTypes.isNotEmpty()) { + // Any source change or any source impacted by type change invalidates aggregating APs generated types + impactedTypes.addAll(aggregatingGeneratedTypes) + } + aptCache.getIsolatingGeneratedTypesForOrigins(changes.dirtyFqNamesFromClasspath, javaCache::getTypesForFiles).let { + if (it.isNotEmpty()) { + impactedTypes.addAll(it) + impactedTypes.addAll(aggregatingGeneratedTypes) + } + } + aptCache.getIsolatingGeneratedTypesForOrigins(impactedTypes, javaCache::getTypesForFiles).let { + impactedTypes.addAll(it) + } + return impactedTypes } private fun maybeGetAptCacheFromFile(): IncrementalAptCache { diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt index 997fc5398bf..0bf8dc97aa5 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/classStructureCache.kt @@ -11,17 +11,18 @@ import java.io.ObjectOutputStream import java.io.Serializable import java.lang.IllegalArgumentException import java.net.URI -import java.util.regex.Pattern +/** + * Stores type information about processed and generated sources. For .java files a fine-grained type information + * exists i.e we know all referenced types. For .class files we only know which type is defined in the .class file. + */ class JavaClassCache() : Serializable { private var sourceCache = mutableMapOf() - /** Record these separately because we only need to know where each generated type is coming from. */ - private var generatedTypes = mutableMapOf>() - /** Map from types to files they are mentioned in. */ @Transient private var dependencyCache = mutableMapOf>() + @Transient private var nonTransitiveCache = mutableMapOf>() @@ -29,21 +30,31 @@ class JavaClassCache() : Serializable { sourceCache[sourceStructure.sourceFile] = sourceStructure } - fun addGeneratedType(type: String, generatedFile: File) { - val typesInFile = generatedTypes[generatedFile] ?: ArrayList(1) - typesInFile.add(type) - generatedTypes[generatedFile] = typesInFile + /** Invalidates types for these files, and return the list of invalidated types.*/ + fun invalidateTypesForFiles(files: List): Set { + val typesFromFiles = HashSet() + for (file in files) { + sourceCache.remove(file.toURI())?.getDeclaredTypes()?.let { + typesFromFiles.addAll(it) + } + } + return typesFromFiles } - fun invalidateGeneratedTypes(files: List): Set { - return files.mapNotNull { generatedTypes.remove(it) }.flatten().toSet() + /** Returns all types defined in these files. */ + fun getTypesForFiles(files: Collection): Set { + val typesFromFiles = HashSet(files.size) + for (file in files) { + sourceCache[file.toURI()]?.getDeclaredTypes()?.let { + typesFromFiles.addAll(it) + } + } + return typesFromFiles } private fun readObject(input: ObjectInputStream) { @Suppress("UNCHECKED_CAST") sourceCache = input.readObject() as MutableMap - @Suppress("UNCHECKED_CAST") - generatedTypes = input.readObject() as MutableMap> dependencyCache = HashMap(sourceCache.size * 4) for (sourceInfo in sourceCache.values) { @@ -71,7 +82,6 @@ class JavaClassCache() : Serializable { private fun writeObject(output: ObjectOutputStream) { output.writeObject(sourceCache) - output.writeObject(generatedTypes) } fun isAlreadyProcessed(sourceFile: URI): Boolean { @@ -84,8 +94,7 @@ class JavaClassCache() : Serializable { return true } return try { - val fileFromUri = File(sourceFile) - sourceCache.containsKey(sourceFile) || generatedTypes.containsKey(fileFromUri) + sourceCache.containsKey(sourceFile) } catch (e: IllegalArgumentException) { // unable to create File instance, avoid processing these files true @@ -96,89 +105,66 @@ class JavaClassCache() : Serializable { internal fun getStructure(sourceFile: File) = sourceCache[sourceFile.toURI()] /** - * Invalidate cache entries for the specified files, and any files that depend on the changed ones. It returns the set of files that - * should be re-processed. - * */ - fun invalidateEntriesForChangedFiles(changes: Changes): SourcesToReprocess { - val allDirtyFiles = mutableSetOf() - var currentDirtyFiles = changes.sourceChanges.map { it.toURI() }.toMutableSet() - - for (classpathFqName in changes.dirtyFqNamesFromClasspath) { - nonTransitiveCache[classpathFqName]?.let { - allDirtyFiles.addAll(it) + * Compute the list of types that are impacted by source changes i.e [Changes.sourceChanges] and [Changes.dirtyFqNamesFromClasspath] + * i.e classpath changes. The search is transitive, if a file is impacted, all files referencing types defined in that file are + * also considered impacted. Only original sources and generated sources are reported as impacted (final result does not contain + * classpath types). + */ + fun getAllImpactedTypes(changes: Changes): MutableSet { + fun findImpactedTypes(changedType: String, transitiveDeps: MutableSet, nonTransitiveDeps: MutableSet) { + dependencyCache[changedType]?.let { impactedSources -> + impactedSources.forEach { + transitiveDeps.addAll(sourceCache.getValue(it).getDeclaredTypes()) + } } - - dependencyCache[classpathFqName]?.let { - currentDirtyFiles.addAll(it) + nonTransitiveCache[changedType]?.let { impactedSources -> + impactedSources.forEach { + nonTransitiveDeps.addAll(sourceCache.getValue(it).getDeclaredTypes()) + } } } val allDirtyTypes = mutableSetOf() + var currentDirtyTypes = getTypesForFiles(changes.sourceChanges).toMutableSet() - while (currentDirtyFiles.isNotEmpty()) { + changes.dirtyFqNamesFromClasspath.forEach { classpathChange -> + findImpactedTypes(classpathChange, currentDirtyTypes, allDirtyTypes) + } - val nextRound = mutableSetOf() - for (dirtyFile in currentDirtyFiles) { - allDirtyFiles.add(dirtyFile) - - val structure = sourceCache.remove(dirtyFile) ?: continue - val dirtyTypes = structure.getDeclaredTypes() - allDirtyTypes.addAll(dirtyTypes) - - dirtyTypes.forEach { type -> - nonTransitiveCache[type]?.let { - allDirtyFiles.addAll(it) - } - - dependencyCache[type]?.let { - nextRound.addAll(it) - } - } + while (currentDirtyTypes.isNotEmpty()) { + val nextRound = mutableSetOf() + for (dirtyType in currentDirtyTypes) { + allDirtyTypes.add(dirtyType) + findImpactedTypes(dirtyType, nextRound, allDirtyTypes) } - currentDirtyFiles = nextRound.filter { !allDirtyFiles.contains(it) }.toMutableSet() + currentDirtyTypes = nextRound.filterTo(HashSet()) { it !in allDirtyTypes } } - - return SourcesToReprocess.Incremental(allDirtyFiles.map { File(it) }, allDirtyTypes, emptyList()) - } - - /** - * For aggregating annotation processors, we always need to reprocess all files annotated with an annotation claimed by the aggregating - * annotation processor. This search is not transitive. - */ - fun invalidateEntriesAnnotatedWith(annotations: Set): Set { - val patterns: List = if ("*" in annotations) { - // optimize this case - create only one pattern - listOf(Pattern.compile(".*")) - } else { - annotations.map { - Pattern.compile( - // These are already valid import statements, otherwise run fails when loading the annotation processor. - // Handles structure; TypeName [.*] e.g. org.jetbrains.annotations.NotNull and org.jetbrains.annotations.* - it.replace(".", "\\.").replace("*", ".+") - ) - } - } - val matchesAnyPattern = { name: String -> patterns.any { it.matcher(name).matches() } } - - val toReprocess = mutableSetOf() - - for (cacheEntry in sourceCache) { - if (cacheEntry.value.getMentionedAnnotations().any(matchesAnyPattern)) { - toReprocess.add(cacheEntry.key) - } - } - - toReprocess.forEach { - sourceCache.remove(it) - } - - return toReprocess.map { File(it) }.toSet() + return allDirtyTypes } internal fun invalidateAll() { sourceCache.clear() - generatedTypes.clear() + } + + fun getSourceForType(type: String): File? { + sourceCache.forEach { (fileUri, typeInfo) -> + if (type in typeInfo.getDeclaredTypes()) { + return File(fileUri) + } + } + return null + } + + fun invalidateDataForTypes(impactedTypes: MutableSet) { + val allSources = mutableSetOf() + sourceCache.forEach { (fileUri, typeInfo) -> + if (typeInfo.getDeclaredTypes().any { it in impactedTypes }) { + allSources.add(fileUri) + } + } + + allSources.forEach { sourceCache.remove(it) } } } diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt index ae2c4361272..109b9a30e0e 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/incrementalProcessors.kt @@ -70,11 +70,17 @@ class IncrementalProcessor(private val processor: Processor, private val kind: D } fun isUnableToRunIncrementally() = !kind.canRunIncrementally - fun getGeneratedToSources() = dependencyCollector.value.getGeneratedToSources() - fun getGeneratedToSourcesAll() = dependencyCollector.value.getGeneratedToSourcesAll() - fun getAggregatedTypes() = dependencyCollector.value.getAggregatedTypes() - fun getRuntimeType(): RuntimeProcType = dependencyCollector.value.getRuntimeType() + /** Mapping fromm generated file to type that were used as originating elements. For aggregating APs types will be [null]. */ + fun getGeneratedToSources(): Map = dependencyCollector.value.getGeneratedToSources() + + /** All top-level types that were processed by aggregating APs. */ + fun getAggregatedTypes() = dependencyCollector.value.getAggregatedTypes() + + /** Mapping from generated class file to type defined in that file. */ + fun getGeneratedClassFilesToTypes(): Map = dependencyCollector.value.getGeneratedClassFilesToTypes() + + fun getRuntimeType(): RuntimeProcType = dependencyCollector.value.getRuntimeType() override fun process(annotations: Set, roundEnv: RoundEnvironment): Boolean { if (getRuntimeType() == RuntimeProcType.AGGREGATING) { @@ -122,8 +128,9 @@ internal class AnnotationProcessorDependencyCollector( private val runtimeProcType: RuntimeProcType, private val warningCollector: (String) -> Unit ) { - private val generatedToSource = mutableMapOf?>() + private val generatedToSource = mutableMapOf() private val aggregatedTypes = mutableSetOf() + private val generatedClassFilesToTypes = mutableMapOf() private var isFullRebuild = !runtimeProcType.isIncremental @@ -131,7 +138,7 @@ internal class AnnotationProcessorDependencyCollector( if (isFullRebuild) return if (supportedAnnotationTypes.contains("*")) { - aggregatedTypes.addAll(getTopLevelClassNames(roundEnv.rootElements?.filterNotNull() ?: emptyList())) + aggregatedTypes.addAll(getTopLevelClassNames(roundEnv.rootElements?.filterNotNull() ?: emptySet())) } else { for (annotation in annotations) { aggregatedTypes.addAll( @@ -149,31 +156,40 @@ internal class AnnotationProcessorDependencyCollector( if (isFullRebuild) return val generatedFile = File(createdFile) + if (generatedFile.extension == "class") { + if (classId == null) { + isFullRebuild = true + warningCollector.invoke( + "Unable to determine type defined in $generatedFile." + ) + return + } + generatedClassFilesToTypes[generatedFile] = classId + } + if (runtimeProcType == RuntimeProcType.AGGREGATING) { - generatedToSource[generatedFile] = classId to null + generatedToSource[generatedFile] = null } else { - val srcFiles = getSrcFiles(originatingElements) - if (srcFiles.size != 1) { + val srcClasses = getTopLevelClassNames(originatingElements.filterNotNull()) + if (srcClasses.size != 1) { isFullRebuild = true warningCollector.invoke( "Expected 1 originating source file when generating $generatedFile, " + - "but detected ${srcFiles.size}: [${srcFiles.joinToString()}]." + "but detected ${srcClasses.size}: [${srcClasses.joinToString()}]." ) } else { - generatedToSource[generatedFile] = classId to srcFiles.single() + generatedToSource[generatedFile] = srcClasses.single() } } } - internal fun getGeneratedToSources(): Map = if (isFullRebuild) emptyMap() else generatedToSource.mapValues { (_, value) -> - value?.second - } - - internal fun getGeneratedToSourcesAll(): Map?> = - if (isFullRebuild) emptyMap() else generatedToSource + /** Mapping from generated files to top level class names that cause that file generation. */ + internal fun getGeneratedToSources(): Map = if (isFullRebuild) emptyMap() else generatedToSource internal fun getAggregatedTypes(): Set = if (isFullRebuild) emptySet() else aggregatedTypes + internal fun getGeneratedClassFilesToTypes(): Map = if (isFullRebuild) emptyMap() else generatedClassFilesToTypes + internal fun getRuntimeType(): RuntimeProcType { return if (isFullRebuild) { RuntimeProcType.NON_INCREMENTAL @@ -183,17 +199,6 @@ internal class AnnotationProcessorDependencyCollector( } } -private fun getSrcFiles(elements: Array): Set { - return elements.filterNotNull().mapNotNull { elem -> - var origin = elem - while (origin.enclosingElement != null && origin.enclosingElement !is PackageElement) { - origin = origin.enclosingElement - } - val uri = (origin as? Symbol.ClassSymbol)?.sourcefile?.toUri()?.takeIf { it.isAbsolute } - uri?.let { File(it).canonicalFile } - }.toSet() -} - private const val PACKAGE_TYPE_NAME = "package-info" fun getElementName(current: Element?): String? { @@ -211,8 +216,8 @@ fun getElementName(current: Element?): String? { return null } -private fun getTopLevelClassNames(elements: Collection): Collection { - return elements.mapNotNull { elem -> +private fun getTopLevelClassNames(elements: Collection): Set { + return elements.mapNotNullTo(HashSet()) { elem -> var origin = elem while (origin.enclosingElement != null && origin.enclosingElement !is PackageElement) { origin = origin.enclosingElement diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt index 28288c05928..fb56aca486b 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/incremental/javacVisitors.kt @@ -246,28 +246,4 @@ private class ConstantTreeVisitor(val sourceStructure: SourceFileStructure) : Tr sourceStructure.addMentionedConstant(containingClass.qualifiedName.toString(), name.toString()) } -} - -class GeneratedTypesTaskListener(private val cache: JavaClassCache) : TaskListener { - - override fun started(e: TaskEvent) { - // do nothing, we just process on finish - } - - override fun finished(e: TaskEvent) { - if (e.kind != TaskEvent.Kind.ENTER || cache.isAlreadyProcessed(e.sourceFile.toUri())) return - - val treeVisitor = object : SimpleTreeVisitor() { - override fun visitClass(node: ClassTree, p: Void?): Void? { - node as JCTree.JCClassDecl - cache.addGeneratedType(node.sym.fullname.toString(), File(e.sourceFile.toUri())) - - node.members.forEach { visit(it, null) } - return null - } - } - e.compilationUnit.typeDecls.forEach { - it.accept(treeVisitor, null) - } - } } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/DynamicIncrementalProcessorTest.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/DynamicIncrementalProcessorTest.kt index e2a84e771ab..3a47751a47d 100644 --- a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/DynamicIncrementalProcessorTest.kt +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/DynamicIncrementalProcessorTest.kt @@ -36,8 +36,8 @@ class DynamicIncrementalProcessorTest { assertEquals( mapOf( - generatedSources.resolve("test/UserGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/User.java").absoluteFile, - generatedSources.resolve("test/AddressGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/Address.java").absoluteFile + generatedSources.resolve("test/UserGenerated.java") to "test.User", + generatedSources.resolve("test/AddressGenerated.java") to "test.Address" ), dynamic.getGeneratedToSources() ) diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/IsolatingIncrementalProcessorTest.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/IsolatingIncrementalProcessorTest.kt index 223fa12b06a..06b28649244 100644 --- a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/IsolatingIncrementalProcessorTest.kt +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/IsolatingIncrementalProcessorTest.kt @@ -35,8 +35,8 @@ class IsolationgIncrementalProcessorTest { assertEquals( mapOf( - generatedSources.resolve("test/UserGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/User.java").absoluteFile, - generatedSources.resolve("test/AddressGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/Address.java").absoluteFile + generatedSources.resolve("test/UserGenerated.java") to "test.User", + generatedSources.resolve("test/AddressGenerated.java") to "test.Address" ), isolating.getGeneratedToSources() ) @@ -62,12 +62,12 @@ class IsolationgIncrementalProcessorTest { assertEquals( mapOf( - generatedSources.resolve("test/UserGenerated.java") to TEST_DATA_DIR.resolve("User.java").absoluteFile, - generatedSources.resolve("test/UserGeneratedClass.class") to TEST_DATA_DIR.resolve("User.java").absoluteFile, - generatedSources.resolve("test/UserGeneratedResource") to TEST_DATA_DIR.resolve("User.java").absoluteFile, - generatedSources.resolve("test/AddressGenerated.java") to TEST_DATA_DIR.resolve("Address.java").absoluteFile, - generatedSources.resolve("test/AddressGeneratedClass.class") to TEST_DATA_DIR.resolve("Address.java").absoluteFile, - generatedSources.resolve("test/AddressGeneratedResource") to TEST_DATA_DIR.resolve("Address.java").absoluteFile + generatedSources.resolve("test/UserGenerated.java") to "test.User", + generatedSources.resolve("test/UserGeneratedClass.class") to "test.User", + generatedSources.resolve("test/UserGeneratedResource") to "test.User", + generatedSources.resolve("test/AddressGenerated.java") to "test.Address", + generatedSources.resolve("test/AddressGeneratedClass.class") to "test.Address", + generatedSources.resolve("test/AddressGeneratedResource") to "test.Address" ), isolating.getGeneratedToSources() ) @@ -95,15 +95,15 @@ class IsolationgIncrementalProcessorTest { isolating.forEach { assertEquals(RuntimeProcType.ISOLATING, it.getRuntimeType()) } assertEquals( mapOf( - generatedSources.resolve("test/UserGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/User.java").absoluteFile, - generatedSources.resolve("test/AddressGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/Address.java").absoluteFile + generatedSources.resolve("test/UserGenerated.java") to "test.User", + generatedSources.resolve("test/AddressGenerated.java") to "test.Address" ), isolating[0].getGeneratedToSources() ) assertEquals( mapOf( - generatedSources.resolve("test/UserGeneratedTwo.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/User.java").absoluteFile, - generatedSources.resolve("test/AddressGeneratedTwo.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/Address.java").absoluteFile + generatedSources.resolve("test/UserGeneratedTwo.java") to "test.User", + generatedSources.resolve("test/AddressGeneratedTwo.java") to "test.Address" ), isolating[1].getGeneratedToSources() ) } @@ -116,7 +116,7 @@ class IsolationgIncrementalProcessorTest { assertEquals( mapOf( - generatedSources.resolve("test/UserGenerated.java") to File("plugins/kapt3/kapt3-base/testData/runner/incremental/User.java").absoluteFile + generatedSources.resolve("test/UserGenerated.java") to "test.User" ), isolating[0].getGeneratedToSources() ) } diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/JavaClassCacheManagerTest.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/JavaClassCacheManagerTest.kt index 845cfb6345a..f3c704c24eb 100644 --- a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/JavaClassCacheManagerTest.kt +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/JavaClassCacheManagerTest.kt @@ -12,7 +12,6 @@ import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder import java.io.File -import java.io.ObjectOutputStream class JavaClassCacheManagerTest { @@ -56,7 +55,8 @@ class JavaClassCacheManagerTest { } prepareForIncremental() - val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(File("Mentioned.java")), emptyList()) as SourcesToReprocess.Incremental + val dirtyFiles = + cache.invalidateAndGetDirtyFiles(listOf(File("Mentioned.java").absoluteFile), emptyList()) as SourcesToReprocess.Incremental assertEquals( listOf( File("Mentioned.java").absoluteFile, @@ -84,7 +84,8 @@ class JavaClassCacheManagerTest { } prepareForIncremental() - val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(File("Mentioned.java")), emptyList()) as SourcesToReprocess.Incremental + val dirtyFiles = + cache.invalidateAndGetDirtyFiles(listOf(File("Mentioned.java").absoluteFile), emptyList()) as SourcesToReprocess.Incremental assertEquals( listOf( File("Mentioned.java").absoluteFile, @@ -112,7 +113,8 @@ class JavaClassCacheManagerTest { } prepareForIncremental() - val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(File("TwoTypes.java")), emptyList()) as SourcesToReprocess.Incremental + val dirtyFiles = + cache.invalidateAndGetDirtyFiles(listOf(File("TwoTypes.java").absoluteFile), emptyList()) as SourcesToReprocess.Incremental assertEquals( listOf( File("TwoTypes.java").absoluteFile, @@ -155,7 +157,7 @@ class JavaClassCacheManagerTest { val dirtyFiles = cache.invalidateAndGetDirtyFiles( - listOf(File("Constants.java")), emptyList() + listOf(File("Constants.java").absoluteFile), emptyList() ) as SourcesToReprocess.Incremental assertEquals( listOf(File("Constants.java").absoluteFile, File("MentionsConst.java").absoluteFile), @@ -163,30 +165,6 @@ class JavaClassCacheManagerTest { ) } - @Test - fun testWithAnnotations() { - SourceFileStructure(File("Annotated1.java").toURI()).also { - it.addDeclaredType("test.Annotated1") - it.addMentionedAnnotations("test.Annotation") - cache.javaCache.addSourceStructure(it) - } - SourceFileStructure(File("Annotated2.java").toURI()).also { - it.addDeclaredType("test.Annotated2") - it.addMentionedAnnotations("com.test.MyAnnotation") - cache.javaCache.addSourceStructure(it) - } - SourceFileStructure(File("Annotated3.java").toURI()).also { - it.addDeclaredType("test.Annotated3") - it.addMentionedAnnotations("Runnable") - cache.javaCache.addSourceStructure(it) - } - prepareForIncremental() - - assertEquals(setOf(File("Annotated1.java").absoluteFile), cache.javaCache.invalidateEntriesAnnotatedWith(setOf("test.Annotation"))) - assertEquals(setOf(File("Annotated2.java").absoluteFile), cache.javaCache.invalidateEntriesAnnotatedWith(setOf("com.test.*"))) - assertEquals(setOf(File("Annotated3.java").absoluteFile), cache.javaCache.invalidateEntriesAnnotatedWith(setOf("*"))) - } - private fun prepareForIncremental() { cache.close() cache = JavaClassCacheManager(cacheDir) diff --git a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt index e7af1dbc5b6..abb1259d2d2 100644 --- a/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt +++ b/plugins/kapt3/kapt3-base/test/org/jetbrains/kotlin/kapt3/base/incremental/TestSimpleIncrementalAptCache.kt @@ -36,7 +36,7 @@ class TestSimpleIncrementalAptCache { fun testAggregatingAnnotations() { runProcessor(SimpleProcessor().toAggregating()) - val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(TEST_DATA_DIR.resolve("User.java")), emptyList()) as SourcesToReprocess.Incremental + val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(TEST_DATA_DIR.resolve("User.java").absoluteFile), emptyList()) as SourcesToReprocess.Incremental assertEquals( listOf(TEST_DATA_DIR.resolve("User.java").absoluteFile, TEST_DATA_DIR.resolve("Address.java").absoluteFile), dirtyFiles.toReprocess @@ -49,7 +49,7 @@ class TestSimpleIncrementalAptCache { fun testIsolatingAnnotations() { runProcessor(SimpleProcessor().toIsolating()) - val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(TEST_DATA_DIR.resolve("User.java")), emptyList()) as SourcesToReprocess.Incremental + val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(TEST_DATA_DIR.resolve("User.java").absoluteFile), emptyList()) as SourcesToReprocess.Incremental assertFalse(generatedSources.resolve("test/UserGenerated.java").exists()) assertEquals( listOf(TEST_DATA_DIR.resolve("User.java").absoluteFile), @@ -61,7 +61,7 @@ class TestSimpleIncrementalAptCache { fun testNonIncremental() { runProcessor(SimpleProcessor().toNonIncremental()) - val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(TEST_DATA_DIR.resolve("User.java")), emptyList()) + val dirtyFiles = cache.invalidateAndGetDirtyFiles(listOf(TEST_DATA_DIR.resolve("User.java").absoluteFile), emptyList()) assertTrue(dirtyFiles is SourcesToReprocess.FullRebuild) }