Shortcut quick fix for migrating all coroutines in the project (KT-27164)
#KT-27164 Fixed
This commit is contained in:
+64
-3
@@ -5,9 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.inspections.migration
|
package org.jetbrains.kotlin.idea.inspections.migration
|
||||||
|
|
||||||
|
import com.intellij.analysis.AnalysisScope
|
||||||
import com.intellij.codeInspection.*
|
import com.intellij.codeInspection.*
|
||||||
|
import com.intellij.codeInspection.actions.RunInspectionIntention
|
||||||
|
import com.intellij.codeInspection.ex.InspectionManagerEx
|
||||||
|
import com.intellij.codeInspection.ex.InspectionProfileImpl
|
||||||
|
import com.intellij.codeInspection.ex.InspectionToolWrapper
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.config.LanguageVersion
|
import org.jetbrains.kotlin.config.LanguageVersion
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
@@ -22,6 +28,7 @@ import org.jetbrains.kotlin.idea.quickfix.migration.MigrationFix
|
|||||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
|
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
|
||||||
|
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
|
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -82,6 +89,52 @@ private interface CoroutineMigrationProblem {
|
|||||||
fun report(holder: ProblemsHolder, isOnTheFly: Boolean, simpleNameExpression: KtSimpleNameExpression): Boolean
|
fun report(holder: ProblemsHolder, isOnTheFly: Boolean, simpleNameExpression: KtSimpleNameExpression): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shortcut quick fix for running inspection in the project scope.
|
||||||
|
// Should work like RunInspectionAction.runInspection.
|
||||||
|
private class ObsoleteCoroutineUsageInWholeFix : LocalQuickFix {
|
||||||
|
override fun getFamilyName(): String = "Fix experimental coroutines usages in the project"
|
||||||
|
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
|
val toolWrapper = InspectionProjectProfileManager.getInstance(project).currentProfile.getInspectionTool(
|
||||||
|
ObsoleteExperimentalCoroutinesInspection().shortName,
|
||||||
|
project
|
||||||
|
)!!
|
||||||
|
|
||||||
|
runToolInProject(project, toolWrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun startInWriteAction(): Boolean = false
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val INSTANCE = ObsoleteCoroutineUsageInWholeFix()
|
||||||
|
|
||||||
|
private fun runToolInProject(project: Project, toolWrapper: InspectionToolWrapper<*, *>) {
|
||||||
|
val managerEx = InspectionManager.getInstance(project) as InspectionManagerEx
|
||||||
|
val kotlinSourcesScope: GlobalSearchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.allScope(project), project)
|
||||||
|
val cleanupScope = AnalysisScope(kotlinSourcesScope, project)
|
||||||
|
|
||||||
|
val cleanupToolProfile = runInInspectionProfileInitMode { RunInspectionIntention.createProfile(toolWrapper, managerEx, null) }
|
||||||
|
managerEx.createNewGlobalContext(false)
|
||||||
|
.codeCleanup(cleanupScope, cleanupToolProfile, "Apply in the project: " + toolWrapper.displayName, null, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overcome failure during profile createin because of absent tools in tests
|
||||||
|
inline fun <T> runInInspectionProfileInitMode(runnable: () -> T): T {
|
||||||
|
return if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||||
|
runnable()
|
||||||
|
} else {
|
||||||
|
val old = InspectionProfileImpl.INIT_INSPECTIONS
|
||||||
|
try {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = true
|
||||||
|
runnable()
|
||||||
|
} finally {
|
||||||
|
InspectionProfileImpl.INIT_INSPECTIONS = old
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There should be a single fix class with the same family name, this way it can be executed for all found coroutines problems from UI.
|
* There should be a single fix class with the same family name, this way it can be executed for all found coroutines problems from UI.
|
||||||
*/
|
*/
|
||||||
@@ -117,6 +170,14 @@ private fun isTopLevelCallForReplace(simpleNameExpression: KtSimpleNameExpressio
|
|||||||
return !isInIndex
|
return !isInIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fixesWithWholeProject(isOnTheFly: Boolean, fix: LocalQuickFix): Array<LocalQuickFix> {
|
||||||
|
if (!isOnTheFly) {
|
||||||
|
return arrayOf(fix)
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrayOf(fix, ObsoleteCoroutineUsageInWholeFix.INSTANCE)
|
||||||
|
}
|
||||||
|
|
||||||
private class ObsoleteTopLevelFunctionUsage(
|
private class ObsoleteTopLevelFunctionUsage(
|
||||||
val textMarker: String, val oldFqName: String, val newFqName: String
|
val textMarker: String, val oldFqName: String, val newFqName: String
|
||||||
) : CoroutineMigrationProblem {
|
) : CoroutineMigrationProblem {
|
||||||
@@ -131,7 +192,7 @@ private class ObsoleteTopLevelFunctionUsage(
|
|||||||
simpleNameExpression,
|
simpleNameExpression,
|
||||||
"`$newFqName` is expected to be used since Kotlin 1.3",
|
"`$newFqName` is expected to be used since Kotlin 1.3",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
ObsoleteCoroutineUsageFix(fix)
|
*fixesWithWholeProject(isOnTheFly, ObsoleteCoroutineUsageFix(fix))
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -167,7 +228,7 @@ private class ObsoleteExtensionFunctionUsage(
|
|||||||
simpleNameExpression,
|
simpleNameExpression,
|
||||||
"Methods are absent in coroutines class since 1.3",
|
"Methods are absent in coroutines class since 1.3",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
ObsoleteCoroutineUsageFix(fix)
|
*fixesWithWholeProject(isOnTheFly, ObsoleteCoroutineUsageFix(fix))
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -207,7 +268,7 @@ private class ExperimentalImportUsage : CoroutineMigrationProblem {
|
|||||||
reportExpression,
|
reportExpression,
|
||||||
"Experimental coroutines usages are obsolete since 1.3",
|
"Experimental coroutines usages are obsolete since 1.3",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
ObsoleteCoroutineUsageFix(ObsoleteCoroutineImportFix)
|
*fixesWithWholeProject(isOnTheFly, ObsoleteCoroutineUsageFix(ObsoleteCoroutineImportFix))
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// "Fix experimental coroutines usages in the project" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
package migrate
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.buildIterator
|
||||||
|
import kotlin.coroutines.experimental.buildSequence
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val one = <caret>buildSequence {
|
||||||
|
yield(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val two = buildIterator {
|
||||||
|
yield(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// "Fix experimental coroutines usages in the project" "true"
|
||||||
|
// WITH_RUNTIME
|
||||||
|
package migrate
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val one = sequence {
|
||||||
|
yield(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
val two = iterator {
|
||||||
|
yield(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8347,6 +8347,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
runTest("idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt");
|
runTest("idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inProjectFix.kt")
|
||||||
|
public void testInProjectFix() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/obsoleteCoroutines/inProjectFix.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("resume.kt")
|
@TestMetadata("resume.kt")
|
||||||
public void testResume() throws Exception {
|
public void testResume() throws Exception {
|
||||||
runTest("idea/testData/quickfix/obsoleteCoroutines/resume.kt");
|
runTest("idea/testData/quickfix/obsoleteCoroutines/resume.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user