From 2e3b3da0295f79c152a76cb0532056aaaab8ed79 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 25 Jul 2016 20:55:44 +0300 Subject: [PATCH] Track changes in generated source files #KT-12962 fixed --- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 6 +++ .../internal/AnnotationProcessingManager.kt | 42 +++++++++++++++++++ .../kotlin/gradle/plugin/KotlinPlugin.kt | 11 ++--- .../AbstractKotlinAndroidGradleTests.kt | 29 +++++++++++-- .../org/jetbrains/kotlin/gradle/KaptIT.kt | 6 +-- .../kotlin/gradle/KaptIncrementalIT.kt | 10 ++++- .../AndroidDaggerProject/app/build.gradle | 1 + .../example/dagger/kotlin/UseRJavaActivity.kt | 9 ++++ .../dagger/kotlin/useBuildConfigJava.kt | 5 +++ 9 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/UseRJavaActivity.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/useBuildConfigJava.kt diff --git a/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 51aa35661b3..1405fd6e932 100644 --- a/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin-core/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -203,6 +203,12 @@ open class KotlinCompile() : AbstractKotlinCompile() { logger.kotlinDebug { "friendTaskName = $friendTaskName" } friendTaskName?.let { addFriendPathForTestTask(it) } logger.kotlinDebug("args.moduleName = ${args.moduleName}") + + fun dumpPaths(files: Iterable): String = + "[${files.map { it.canonicalPath }.sorted().joinToString(prefix = "\n\t", separator = ",\n\t")}]" + + logger.kotlinDebug { "$name source roots: ${dumpPaths(sourceRoots)}" } + logger.kotlinDebug { "$name java source roots: ${dumpPaths(getJavaSourceRoots())}" } } override fun callCompiler(args: K2JVMCompilerArguments, sources: List, isIncrementalRequested: Boolean, modified: List, removed: List) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt index 110f9e6e05f..dff6d3614d1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt @@ -21,6 +21,14 @@ import org.gradle.api.Project import org.gradle.api.UnknownDomainObjectException import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.com.intellij.lang.Language +import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer +import org.jetbrains.kotlin.com.intellij.psi.PsiFileFactory +import org.jetbrains.kotlin.com.intellij.psi.PsiJavaFile +import org.jetbrains.kotlin.com.intellij.psi.impl.PsiFileFactoryImpl +import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider @@ -57,6 +65,10 @@ fun Project.initKapt( kotlinAfterJavaTask.source(kaptManager.generatedKotlinSourceDir) kotlinAfterJavaTask.source(kaptManager.aptOutputDir) subpluginEnvironment.addSubpluginArguments(this, kotlinAfterJavaTask) + + javaTask.doLast { + moveGeneratedJavaFilesToCorrespondingDirectories(kaptManager.aptOutputDir) + } } else { kotlinAfterJavaTask = null kotlinTask.logger.kotlinDebug("kapt: Class file stubs are not used") @@ -336,4 +348,34 @@ public class AnnotationProcessingManager( project.logger.kotlinDebug("kapt: Discovered annotation processors: ${annotationProcessors.joinToString()}") return annotationProcessors } +} + +// Java files can be generated anywhere, but +// Kotlin searches for java fq-name only in directory corresponding to package. +// Previously this worked because generated files were added to classpath. +// However in that case incremental compilation worked unreliable with generated files. +// The solution is to post-process generated java files and move them to corresponding packages +fun moveGeneratedJavaFilesToCorrespondingDirectories(generatedJavaSourceRoot: File) { + val javaFiles = generatedJavaSourceRoot.walk().filter { it.extension.equals("java", ignoreCase = true) }.toList() + + if (javaFiles.isEmpty()) return + + val rootDisposable = Disposer.newDisposable() + val configuration = CompilerConfiguration() + val environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) + val project = environment.project + val psiFileFactory = PsiFileFactory.getInstance(project) as PsiFileFactoryImpl + + for (javaFile in javaFiles) { + val psiFile = psiFileFactory.createFileFromText(javaFile.nameWithoutExtension, Language.findLanguageByID("JAVA")!!, javaFile.readText()) + val packageName = (psiFile as? PsiJavaFile)?.packageName ?: continue + val expectedDir = File(generatedJavaSourceRoot, packageName.replace('.', '/')) + val expectedFile = File(expectedDir, javaFile.name) + + if (javaFile != expectedFile) { + expectedFile.parentFile.mkdirs() + javaFile.copyTo(expectedFile, overwrite = true) + javaFile.delete() + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 5eb542f3f48..b39ef5edb8a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -70,7 +70,7 @@ abstract class KotlinSourceSetProcessor( if (kotlinSourceSet == null || kotlinDirSet == null) { return } - addSourcesToKotlinDirSet() + addKotlinDirSetToSources() commonTaskConfiguration() doTargetSpecificProcessing() } @@ -93,10 +93,10 @@ abstract class KotlinSourceSetProcessor( return kotlinDirSet } - open protected fun addSourcesToKotlinDirSet() { + private fun addKotlinDirSetToSources() { logger.kotlinDebug("Adding Kotlin SourceDirectorySet $kotlinDirSet to source set $sourceSet") - sourceSet.getAllJava()?.source(kotlinDirSet) - sourceSet.getAllSource()?.source(kotlinDirSet) + sourceSet.allJava?.source(kotlinDirSet) + sourceSet.allSource?.source(kotlinDirSet) sourceSet.resources?.filter?.exclude { kotlinDirSet!!.contains(it.file) } } @@ -152,7 +152,7 @@ class Kotlin2JvmSourceSetProcessor( if (project != null) { kotlinTask.destinationDir = File(project.buildDir, "kotlin-classes/$sourceSetName") - for (dir in sourceSet.getJava().srcDirs) { + for (dir in sourceSet.java.srcDirs) { kotlinDirSet?.srcDir(dir) } @@ -175,6 +175,7 @@ class Kotlin2JvmSourceSetProcessor( kotlinAfterJavaTask = project.initKapt(kotlinTask, javaTask, kaptManager, sourceSetName, null, subpluginEnvironment, tasksProvider) } + kotlinAfterJavaTask?.let { it.source(kotlinDirSet) } configureJavaTask(kotlinTask, javaTask, kotlinAfterJavaTask, logger) createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, sourceSetName) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index 5283a1ad55d..4bd1b5d94e4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -142,13 +142,34 @@ fun getSomething() = 10 assertSuccessful() } - val file = project.projectDir.getFileByName("AndroidModule.kt") - file.modify { it.replace("fun provideApplicationContext(): Context {", - "fun provideApplicationContext(): Context? {") } + val androidModuleKt = project.projectDir.getFileByName("AndroidModule.kt") + androidModuleKt.modify { it.replace("fun provideApplicationContext(): Context {", + "fun provideApplicationContext(): Context? {") } + // rebuilt because DaggerApplicationComponent.java was regenerated + val baseApplicationKt = project.projectDir.getFileByName("BaseApplication.kt") + // rebuilt because BuildConfig.java was regenerated (timestamp was changed) + val useBuildConfigJavaKt = project.projectDir.getFileByName("useBuildConfigJava.kt") + + val stringsXml = project.projectDir.getFileByName("strings.xml") + stringsXml.modify { """ + + kotlin + kotlin1 + + """ } + // rebuilt because R.java changed + val homeActivityKt = project.projectDir.getFileByName("HomeActivity.kt") + val useRJavaActivity = project.projectDir.getFileByName("UseRJavaActivity.kt") project.build(":app:assembleDebug", options = options) { assertSuccessful() - assertCompiledKotlinSources(project.relativizeToSubproject("app", file)) + assertCompiledKotlinSources(project.relativizeToSubproject("app", + androidModuleKt, + baseApplicationKt, + useBuildConfigJavaKt, + homeActivityKt, + useRJavaActivity + )) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt index 6e43774e2c4..fb1dce753c8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIT.kt @@ -64,7 +64,7 @@ class KaptIT: BaseGradleIT() { assertContains(":compileKotlin") assertContains(":compileJava") assertFileExists("build/tmp/kapt/main/wrappers/annotations.main.txt") - assertFileExists("build/generated/source/kapt/main/TestClassGenerated.java") + assertFileExists("build/generated/source/kapt/main/example/TestClassGenerated.java") assertFileExists("build/classes/main/example/TestClass.class") assertFileExists("build/classes/main/example/TestClassGenerated.class") assertFileExists("build/classes/main/example/SourceAnnotatedTestClassGenerated.class") @@ -149,7 +149,7 @@ class KaptIT: BaseGradleIT() { assertContains(":compileKotlin") assertContains(":compileJava") assertFileExists("build/tmp/kapt/main/wrappers/annotations.main.txt") - assertFileExists("build/generated/source/kapt/main/TestClassCustomized.java") + assertFileExists("build/generated/source/kapt/main/example/TestClassCustomized.java") assertFileExists("build/classes/main/example/TestClass.class") assertFileExists("build/classes/main/example/TestClassCustomized.class") } @@ -174,7 +174,7 @@ class KaptIT: BaseGradleIT() { assertContains(":compileKotlin") assertContains(":compileJava") assertFileExists("build/tmp/kapt/main/wrappers/annotations.main.txt") - assertFileExists("build/generated/source/kapt/main/TestClassCustomized.java") + assertFileExists("build/generated/source/kapt/main/example/TestClassCustomized.java") assertFileExists("build/tmp/kapt/main/kotlinGenerated/TestClass.kt") assertFileExists("build/classes/main/example/TestClass.class") assertFileExists("build/classes/main/example/TestClassCustomized.class") diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt index 559c5f1898d..e9b1048a3f5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalIT.kt @@ -133,8 +133,14 @@ abstract class KaptIncrementalBaseIT(val shouldUseStubs: Boolean): BaseGradleIT( project.build("build") { assertSuccessful() - val useBKt = project.projectDir.getFileByName("useB.kt") - assertCompiledKotlinSources(project.relativize(bKt, useBKt)) + if (shouldUseStubs) { + // java removal is detected + assertCompiledKotlinSources(project.relativize(project.projectDir.allKotlinFiles())) + } + else { + val useBKt = project.projectDir.getFileByName("useB.kt") + assertCompiledKotlinSources(project.relativize(bKt, useBKt)) + } checkGenerated(*(annotatedElements.toSet() - affectedElements).toTypedArray()) checkNotGenerated(*affectedElements) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/build.gradle b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/build.gradle index fd32df79607..a97ff934058 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/build.gradle @@ -29,6 +29,7 @@ android { targetSdkVersion 23 versionCode 1 versionName "1.0" + buildConfigField "long", "BUILD_TIME_MILLIS", "${System.currentTimeMillis()}L" } sourceSets { main.java.srcDirs += 'src/main/kotlin' diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/UseRJavaActivity.kt b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/UseRJavaActivity.kt new file mode 100644 index 00000000000..34b808da2d9 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/UseRJavaActivity.kt @@ -0,0 +1,9 @@ +package com.example.dagger.kotlin + +import android.app.Activity + +class UseRJavaActivity : Activity() { + fun useRJava() { + val app_name = getResources().getString(R.string.app_name) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/useBuildConfigJava.kt b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/useBuildConfigJava.kt new file mode 100644 index 00000000000..4a6718ee884 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/resources/testProject/AndroidDaggerProject/app/src/main/java/com/example/dagger/kotlin/useBuildConfigJava.kt @@ -0,0 +1,5 @@ +package com.example.dagger.kotlin + +fun useBuildConfigJava() { + if (BuildConfig.APPLICATION_ID != "com.example.dagger.kotlin") throw AssertionError() +} \ No newline at end of file