diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/DeprecatedGradleDependencyInspection.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/DeprecatedGradleDependencyInspection.kt index 890465de23c..7c3d23fc036 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/DeprecatedGradleDependencyInspection.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/DeprecatedGradleDependencyInspection.kt @@ -93,7 +93,10 @@ class DeprecatedGradleDependencyInspection : GradleBaseInspection() { return classpathEntry.findElementAt(indexOf) ?: classpathEntry } - private fun libraryVersionFromOrderEntry(file: PsiFile, libraryId: String): String? { + } + + companion object { + fun libraryVersionFromOrderEntry(file: PsiFile, libraryId: String): String? { val module = ProjectRootManager.getInstance(file.project).fileIndex.getModuleForFile(file.virtualFile) ?: return null val libMarker = ":$libraryId:" diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/GradleKotlinxCoroutinesDeprecationInspection.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/GradleKotlinxCoroutinesDeprecationInspection.kt index 7501090d456..7de217cfc15 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/GradleKotlinxCoroutinesDeprecationInspection.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/inspections/gradle/GradleKotlinxCoroutinesDeprecationInspection.kt @@ -12,6 +12,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.idea.configuration.getWholeModuleGroup +import org.jetbrains.kotlin.idea.inspections.ReplaceStringInDocumentFix import org.jetbrains.kotlin.idea.inspections.gradle.GradleHeuristicHelper.PRODUCTION_DEPENDENCY_STATEMENTS import org.jetbrains.kotlin.idea.inspections.migration.DEPRECATED_COROUTINES_LIBRARIES_INFORMATION import org.jetbrains.kotlin.idea.inspections.migration.DeprecatedForKotlinLibInfo @@ -49,11 +50,34 @@ class GradleKotlinxCoroutinesDeprecationInspection : GradleBaseInspection(), Cle return } + val libVersion = + DifferentStdlibGradleVersionInspection.getResolvedLibVersion( + dependencyStatement.containingFile, outdatedInfo.lib.groupId, listOf(outdatedInfo.lib.name) + ) ?: DeprecatedGradleDependencyInspection.libraryVersionFromOrderEntry( + dependencyStatement.containingFile, + outdatedInfo.lib.name + ) ?: continue + + val updatedVersion = outdatedInfo.versionUpdater.updateVersion(libVersion) + if (libVersion == updatedVersion) { + continue + } + + if (dependencyText.contains(updatedVersion)) { + continue + } + val reportOnElement = reportOnElement(dependencyStatement, outdatedInfo) + val fix = if (dependencyText.contains(libVersion)) { + ReplaceStringInDocumentFix(reportOnElement, libVersion, updatedVersion) + } else { + null + } + registerError( reportOnElement, outdatedInfo.message, - emptyArray(), + if (fix != null) arrayOf(fix) else emptyArray(), ProblemHighlightType.GENERIC_ERROR_OR_WARNING ) diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt new file mode 100644 index 00000000000..7bd73080894 --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleQuickFixTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.idea.codeInsight.gradle + +import com.intellij.codeInspection.LocalInspectionTool +import com.intellij.codeInspection.ProblemDescriptorBase +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.impl.LoadTextUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.testFramework.fixtures.CodeInsightTestFixture +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory +import org.jetbrains.kotlin.idea.inspections.gradle.GradleKotlinxCoroutinesDeprecationInspection +import org.jetbrains.kotlin.idea.inspections.runInspection +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.test.testFramework.runInEdtAndWait +import org.junit.Test +import java.io.File +import kotlin.reflect.KMutableProperty0 + +class GradleQuickFixTest : GradleImportingTestCase() { + private lateinit var codeInsightTestFixture: CodeInsightTestFixture + + private fun getTestDataPath() = + PluginTestCaseBase.getTestDataPathBase() + "/gradle/fixes/" + getTestName(true).substringBefore('_') + + override fun setUpFixtures() { + myTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()).fixture + codeInsightTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(myTestFixture) + codeInsightTestFixture.setUp() + } + + override fun tearDownFixtures() { + codeInsightTestFixture.tearDown() + @Suppress("UNCHECKED_CAST") + (this::codeInsightTestFixture as KMutableProperty0).set(null) + myTestFixture = null + } + + @Test + fun testUpdateKotlinxCoroutines() { + doGradleQuickFixTest(GradleKotlinxCoroutinesDeprecationInspection()) + } + + private fun doGradleQuickFixTest(localInspectionTool: LocalInspectionTool) { + val buildGradleVFile = createProjectSubFile("build.gradle", File(getTestDataPath(), "build.gradle").readText()) + importProject() + + applyInspectionFixes(localInspectionTool, buildGradleVFile) + + runInEdtAndWait { + FileDocumentManager.getInstance().saveAllDocuments() + } + + checkResult(buildGradleVFile) + } + + private fun applyInspectionFixes(tool: LocalInspectionTool, file: VirtualFile) { + invokeTestRunnable { + val presentation = runInspection(tool, myProject, listOf(file)) + + WriteCommandAction.runWriteCommandAction(myProject) { + val foundProblems = presentation.problemElements.values.mapNotNull { it as? ProblemDescriptorBase } + for (problem in foundProblems) { + val fixes = problem.fixes + if (fixes != null) { + fixes[0].applyFix(myProject, problem) + } + } + } + } + } + + private fun checkResult(file: VirtualFile) { + KotlinTestUtils.assertEqualsToFile(File(getTestDataPath(), "build.gradle.after"), LoadTextUtil.loadText(file).toString()) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/migration/coroutinesObsoleteLibraries.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/migration/coroutinesObsoleteLibraries.kt index d424b6d3110..86082a93be8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/migration/coroutinesObsoleteLibraries.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/migration/coroutinesObsoleteLibraries.kt @@ -5,12 +5,29 @@ package org.jetbrains.kotlin.idea.inspections.migration +import com.intellij.util.text.VersionComparatorUtil import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.idea.versions.LibInfo +interface VersionUpdater { + fun updateVersion(currentVersion: String): String +} + +object KotlinxVersionUpdater : VersionUpdater { + override fun updateVersion(currentVersion: String): String { + return when { + currentVersion.contains("eap13") -> return currentVersion + (VersionComparatorUtil.compare(currentVersion, "0.30.0") >= 0) -> return currentVersion + (VersionComparatorUtil.compare(currentVersion, "0.24.0") < 0) -> return "0.24.0-eap13" + else -> "$currentVersion-eap13" + } + } +} + data class DeprecatedForKotlinLibInfo( val lib: LibInfo, val sinceKotlinLanguageVersion: LanguageVersion, + val versionUpdater: VersionUpdater, val message: String ) @@ -19,6 +36,7 @@ private fun kotlinxCoroutinesDeprecation(name: String): DeprecatedForKotlinLibIn return DeprecatedForKotlinLibInfo( lib = LibInfo("org.jetbrains.kotlinx", name), sinceKotlinLanguageVersion = LanguageVersion.KOTLIN_1_3, + versionUpdater = KotlinxVersionUpdater, message = "Library should be updated to be compatible with Kotlin 1.3" ) } diff --git a/idea/testData/gradle/fixes/updateKotlinxCoroutines/build.gradle b/idea/testData/gradle/fixes/updateKotlinxCoroutines/build.gradle new file mode 100644 index 00000000000..96e99f7c7ca --- /dev/null +++ b/idea/testData/gradle/fixes/updateKotlinxCoroutines/build.gradle @@ -0,0 +1,27 @@ +group 'Again' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.50") + } +} + +apply plugin: 'kotlin' + +repositories { + mavenCentral() + maven { url "https://kotlin.bintray.com/kotlinx" } +} + +dependencies { + compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4' +} + +compileKotlin { + kotlinOptions.languageVersion = "1.3" +} \ No newline at end of file diff --git a/idea/testData/gradle/fixes/updateKotlinxCoroutines/build.gradle.after b/idea/testData/gradle/fixes/updateKotlinxCoroutines/build.gradle.after new file mode 100644 index 00000000000..67d58b184a6 --- /dev/null +++ b/idea/testData/gradle/fixes/updateKotlinxCoroutines/build.gradle.after @@ -0,0 +1,27 @@ +group 'Again' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.50") + } +} + +apply plugin: 'kotlin' + +repositories { + mavenCentral() + maven { url "https://kotlin.bintray.com/kotlinx" } +} + +dependencies { + compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.24.0-eap13' +} + +compileKotlin { + kotlinOptions.languageVersion = "1.3" +} \ No newline at end of file