Add quickfix for adding CancellableException to @Throws suspend fun
This commit is contained in:
@@ -2229,4 +2229,5 @@ listbox.import.package=Package
|
||||
listbox.import.with.subpackages=With Subpackages
|
||||
title.import.layout=Import Layout
|
||||
title.packages.to.use.import.with=Packages to Use Import with '*'
|
||||
redundant.qualifier.unnecessary.non.direct.parent.class.qualifier=Unnecessary non-direct parent classes qualifiers
|
||||
redundant.qualifier.unnecessary.non.direct.parent.class.qualifier=Unnecessary non-direct parent classes qualifiers
|
||||
fix.add.exception.to.throws=Add ''{0}''
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative.MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND
|
||||
|
||||
class AddExceptionToThrowsFix(
|
||||
element: KtAnnotationEntry,
|
||||
private val argumentClassFqName: FqName
|
||||
) : KotlinQuickFixAction<KtAnnotationEntry>(element) {
|
||||
|
||||
override fun getText(): String = KotlinBundle.message(
|
||||
"fix.add.exception.to.throws",
|
||||
"${argumentClassFqName.shortName().asString()}::class"
|
||||
)
|
||||
|
||||
override fun getFamilyName() = this.text
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val annotationEntry = element ?: return
|
||||
val psiFactory = KtPsiFactory(annotationEntry)
|
||||
|
||||
val argumentText = "${argumentClassFqName.asString()}::class"
|
||||
val added = annotationEntry.valueArgumentList?.addArgument(psiFactory.createArgument(argumentText))
|
||||
|
||||
if (added != null) ShortenReferences.DEFAULT.process(added)
|
||||
}
|
||||
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val annotationEntry = diagnostic.psiElement as? KtAnnotationEntry ?: return null
|
||||
val valueArgumentsList = annotationEntry.valueArgumentList
|
||||
?: return null // Note: shouldn't reach here, frontend doesn't report MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND in this case.
|
||||
|
||||
if (valueArgumentsList.arguments.firstOrNull()?.getArgumentName() != null) {
|
||||
// E.g. @Throws(exceptionClasses = [Foo::class]).
|
||||
// Unsupported at the moment:
|
||||
return null
|
||||
// Note: AddThrowsAnnotationIntention has the code to support this case, but a refactoring is required to use it.
|
||||
}
|
||||
|
||||
val missingExceptionFqName = when (diagnostic.factory) {
|
||||
MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND -> MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND.cast(diagnostic).a
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return AddExceptionToThrowsFix(annotationEntry, missingExceptionFqName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.*
|
||||
import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative.MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND
|
||||
|
||||
class QuickFixRegistrar : QuickFixContributor {
|
||||
override fun registerQuickFixes(quickFixes: QuickFixes) {
|
||||
@@ -651,5 +652,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
TOPLEVEL_TYPEALIASES_ONLY.registerFactory(MoveTypeAliasToTopLevelFix)
|
||||
|
||||
CONFLICTING_JVM_DECLARATIONS.registerFactory(AddJvmNameAnnotationFix)
|
||||
|
||||
MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND.registerFactory(AddExceptionToThrowsFix)
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package kotlin.coroutines.cancellation
|
||||
|
||||
public open class CancellationException() : IllegalStateException()
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
package kotlin
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
public annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)
|
||||
|
||||
public open class Exception : Throwable()
|
||||
|
||||
public open class RuntimeException : Exception()
|
||||
|
||||
public open class IllegalStateException : RuntimeException()
|
||||
|
||||
public open class Error : Throwable()
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// "Add 'CancellationException::class'" "true"
|
||||
|
||||
<caret>@Throws(Error::class)
|
||||
suspend fun addCE() {}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
// "Add 'CancellationException::class'" "true"
|
||||
|
||||
@Throws(Error::class, CancellationException::class)
|
||||
suspend fun addCE() {}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package kotlin
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
public annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
// "Add 'CancellationException::class'" "false"
|
||||
// ERROR: @Throws on suspend declaration must have CancellationException (or any of its superclasses) listed
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
|
||||
class MyException : Throwable()
|
||||
|
||||
// Quickfix doesn't support this case:
|
||||
<caret>@Throws(exceptionClasses = [MyException::class])
|
||||
suspend fun addCE() {}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package kotlin
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
public annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
// "Add 'CancellationException::class'" "false"
|
||||
// ERROR: @Throws must have non-empty class list
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
|
||||
// No compilation error => no quickfix.
|
||||
<caret>@Throws()
|
||||
suspend fun emptyThrows() {}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package kotlin
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
public annotation class Throws(vararg val exceptionClasses: KClass<out Throwable>)
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
// "Add 'CancellationException::class'" "false"
|
||||
// ERROR: @Throws must have non-empty class list
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
|
||||
// No compilation error => no quickfix.
|
||||
<caret>@Throws
|
||||
suspend fun emptyThrows() {}
|
||||
+33
@@ -794,6 +794,39 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/multiModuleQuickFix/fixNativeThrowsErrors")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FixNativeThrowsErrors extends AbstractQuickFixMultiModuleTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("addCancellationException1")
|
||||
public void testAddCancellationException1() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException1/");
|
||||
}
|
||||
|
||||
@TestMetadata("addCancellationException2")
|
||||
public void testAddCancellationException2() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException2/");
|
||||
}
|
||||
|
||||
@TestMetadata("addCancellationException3")
|
||||
public void testAddCancellationException3() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException3/");
|
||||
}
|
||||
|
||||
@TestMetadata("addCancellationException4")
|
||||
public void testAddCancellationException4() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/fixNativeThrowsErrors/addCancellationException4/");
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFixNativeThrowsErrors() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/multiModuleQuickFix/fixNativeThrowsErrors"), Pattern.compile("^([^\\.]+)$"), null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/multiModuleQuickFix/makeOverridenMemberOpen")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user