diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/migration/ObsoleteExperimentalCoroutinesInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/migration/ObsoleteExperimentalCoroutinesInspection.kt index 982c99a888b..36dd77f6129 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/migration/ObsoleteExperimentalCoroutinesInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/migration/ObsoleteExperimentalCoroutinesInspection.kt @@ -12,6 +12,7 @@ import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny +import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests import org.jetbrains.kotlin.idea.configuration.MigrationInfo import org.jetbrains.kotlin.idea.configuration.isLanguageVersionUpdate import org.jetbrains.kotlin.idea.imports.importableFqName @@ -52,10 +53,21 @@ class ObsoleteExperimentalCoroutinesInspection : AbstractKotlinInspection(), Cle companion object { private val PROBLEMS = listOf( + ObsoleteTopLevelFunctionUsage( + "buildSequence", + "kotlin.coroutines.experimental.buildSequence", + "kotlin.sequences.sequence" + ), + ObsoleteTopLevelFunctionUsage( + "buildIterator", + "kotlin.coroutines.experimental.buildIterator", + "kotlin.sequences.iterator" + ), ObsoleteExtensionFunctionUsage( "resume", "kotlin.coroutines.experimental.Continuation.resume", - "kotlin.coroutines.resume"), + "kotlin.coroutines.resume" + ), ObsoleteExtensionFunctionUsage( "resumeWithException", "kotlin.coroutines.experimental.Continuation.resumeWithException", @@ -87,6 +99,56 @@ private class ObsoleteCoroutineUsageFix(val delegate: CoroutineFix) : LocalQuick } } +private class ObsoleteTopLevelFunctionUsage( + val textMarker: String, val oldFqName: String, val newFqName: String +) : CoroutineMigrationProblem { + override fun report(holder: ProblemsHolder, isOnTheFly: Boolean, simpleNameExpression: KtSimpleNameExpression): Boolean { + if (simpleNameExpression.text != textMarker) return false + + if (simpleNameExpression.parent !is KtCallExpression) return false + + val descriptor = simpleNameExpression.resolveMainReferenceToDescriptors().firstOrNull() ?: return false + val callableDescriptor = descriptor as? CallableDescriptor ?: return false + + val resolvedToFqName = callableDescriptor.fqNameOrNull()?.asString() ?: return false + if (resolvedToFqName != oldFqName) return false + + val project = simpleNameExpression.project + + KotlinTopLevelFunctionFqnNameIndex.getInstance() + .get(newFqName, project, GlobalSearchScope.allScope(project)) + .asSequence() + .firstOrNull() ?: return false + + val problemDescriptor = holder.manager.createProblemDescriptor( + simpleNameExpression, + simpleNameExpression, + "`$newFqName` is expected to be used since Kotlin 1.3", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + isOnTheFly, + ObsoleteCoroutineUsageFix(fix) + ) + holder.registerProblem(problemDescriptor) + + return true + } + + private val fix = RebindReferenceFix(newFqName) + + companion object { + private class RebindReferenceFix(val fqName: String) : ObsoleteCoroutineUsageFix.Companion.CoroutineFix { + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val element = descriptor.psiElement + if (element !is KtSimpleNameExpression) return + + element.mainReference.bindToFqName(FqName(fqName), KtSimpleNameReference.ShorteningMode.DELAYED_SHORTENING) + + performDelayedRefactoringRequests(project) + } + } + } +} + private class ObsoleteExtensionFunctionUsage( val textMarker: String, val oldFqName: String, newFqName: String ) : CoroutineMigrationProblem { diff --git a/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt b/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt index 6c0269e1924..cb62eadb5dc 100644 --- a/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt +++ b/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt @@ -1,8 +1,10 @@ // "Fix experimental coroutines usage" "true" -// ERROR: Unresolved reference: buildSequence -import kotlin.coroutines.experimental.buildSequence +// WITH_RUNTIME +package some + +import kotlin.coroutines.experimental.buildSequence fun main(args: Array) { - val lazySeq = buildSequence { + val lazySeq = buildSequence { } } \ No newline at end of file diff --git a/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt.after b/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt.after index d1b2117b0eb..899ed402b8c 100644 --- a/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt.after +++ b/idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt.after @@ -1,7 +1,10 @@ // "Fix experimental coroutines usage" "true" -// ERROR: Unresolved reference: buildSequence +// WITH_RUNTIME +package some + +import kotlin.coroutines.experimental.buildSequence fun main(args: Array) { - val lazySeq = buildSequence { + val lazySeq = sequence { } } \ No newline at end of file diff --git a/idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt b/idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt new file mode 100644 index 00000000000..6c0269e1924 --- /dev/null +++ b/idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt @@ -0,0 +1,8 @@ +// "Fix experimental coroutines usage" "true" +// ERROR: Unresolved reference: buildSequence +import kotlin.coroutines.experimental.buildSequence + +fun main(args: Array) { + val lazySeq = buildSequence { + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt.after b/idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt.after new file mode 100644 index 00000000000..d1b2117b0eb --- /dev/null +++ b/idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt.after @@ -0,0 +1,7 @@ +// "Fix experimental coroutines usage" "true" +// ERROR: Unresolved reference: buildSequence + +fun main(args: Array) { + val lazySeq = buildSequence { + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 126982b7fe1..e3a85e524d4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -8304,6 +8304,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/obsoleteCoroutines/buildSequence.kt"); } + @TestMetadata("buildSequenceImport.kt") + public void testBuildSequenceImport() throws Exception { + runTest("idea/testData/quickfix/obsoleteCoroutines/buildSequenceImport.kt"); + } + @TestMetadata("resume.kt") public void testResume() throws Exception { runTest("idea/testData/quickfix/obsoleteCoroutines/resume.kt");