AddThrowsAnnotationIntention: improve for mpp

#KT-38391 Fixed
This commit is contained in:
Dmitry Gridin
2020-05-19 14:24:43 +07:00
parent 8b4660031f
commit 499a02ebe3
9 changed files with 86 additions and 3 deletions
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.idea.intentions package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.module.Module
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
@@ -17,8 +19,11 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.platform import org.jetbrains.kotlin.idea.project.platform
import org.jetbrains.kotlin.idea.refactoring.fqName.fqName import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.util.addAnnotation import org.jetbrains.kotlin.idea.util.addAnnotation
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
@@ -35,14 +40,18 @@ class AddThrowsAnnotationIntention : SelfTargetingIntention<KtThrowExpression>(
KtThrowExpression::class.java, KotlinBundle.lazyMessage("add.throws.annotation") KtThrowExpression::class.java, KotlinBundle.lazyMessage("add.throws.annotation")
) { ) {
override fun isApplicableTo(element: KtThrowExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtThrowExpression, caretOffset: Int): Boolean {
if (!element.platform.isJvm()) return false if (element.platform.isJs()) return false
val containingDeclaration = element.getContainingDeclaration() ?: return false val containingDeclaration = element.getContainingDeclaration() ?: return false
val type = element.thrownExpression?.resolveToCall()?.resultingDescriptor?.returnType ?: return false val type = element.thrownExpression?.resolveToCall()?.resultingDescriptor?.returnType ?: return false
if ((type.constructor.declarationDescriptor as? DeclarationDescriptorWithVisibility)?.visibility == Visibilities.LOCAL) return false if ((type.constructor.declarationDescriptor as? DeclarationDescriptorWithVisibility)?.visibility == Visibilities.LOCAL) return false
val context = element.analyze(BodyResolveMode.PARTIAL) val module = element.module ?: return false
if (!KOTLIN_THROWS_ANNOTATION_FQ_NAME.fqNameIsExists(module) &&
!(element.platform.isJvm() && JVM_THROWS_ANNOTATION_FQ_NAME.fqNameIsExists(module))
) return false
val context = element.analyze(BodyResolveMode.PARTIAL)
val annotationEntry = containingDeclaration.findThrowsAnnotation(context) ?: return true val annotationEntry = containingDeclaration.findThrowsAnnotation(context) ?: return true
val valueArguments = annotationEntry.valueArguments val valueArguments = annotationEntry.valueArguments
if (valueArguments.isEmpty()) return true if (valueArguments.isEmpty()) return true
@@ -140,3 +149,9 @@ private fun KtPsiFactory.createCollectionLiteral(expressions: List<KtExpression>
appendFixedText(lastExpression) appendFixedText(lastExpression)
appendFixedText("]") appendFixedText("]")
} as KtCollectionLiteralExpression } as KtCollectionLiteralExpression
private fun FqName.fqNameIsExists(module: Module): Boolean = KotlinFullClassNameIndex.getInstance()[
asString(),
module.project,
GlobalSearchScope.moduleWithLibrariesScope(module)
].isNotEmpty()
@@ -0,0 +1,7 @@
// "Add '@Throws' annotation" "true"
class FooException : Exception()
fun test() {
<caret>throw FooException()
}
@@ -0,0 +1,8 @@
// "Add '@Throws' annotation" "true"
class FooException : Exception()
@Throws(FooException::class)
fun test() {
throw FooException()
}
@@ -0,0 +1,5 @@
// "Add '@Throws' annotation" "false"
fun test() {
<caret>throw Throwable()
}
@@ -0,0 +1,5 @@
// "Add '@Throws' annotation" "true"
fun test() {
<caret>throw Throwable()
}
@@ -0,0 +1,6 @@
// "Add '@Throws' annotation" "true"
@Throws(Throwable::class)
fun test() {
<caret>throw Throwable()
}
@@ -0,0 +1,5 @@
// "Add '@Throws' annotation" "false"
fun test() {
<caret>throw Throwable()
}
@@ -1,5 +1,4 @@
// "Add 'return' before the expression" "false" // "Add 'return' before the expression" "false"
// ACTION: Add '@Throws' annotation
fun test(): Nothing { fun test(): Nothing {
<caret>throw Throwable("Error") <caret>throw Throwable("Error")
@@ -209,6 +209,39 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
} }
} }
@TestMetadata("idea/testData/multiModuleQuickFix/addThrowAnnotation")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class AddThrowAnnotation extends AbstractQuickFixMultiModuleTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInAddThrowAnnotation() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/multiModuleQuickFix/addThrowAnnotation"), Pattern.compile("^([^\\.]+)$"), null, true);
}
@TestMetadata("common")
public void testCommon() throws Exception {
runTest("idea/testData/multiModuleQuickFix/addThrowAnnotation/common/");
}
@TestMetadata("js")
public void testJs() throws Exception {
runTest("idea/testData/multiModuleQuickFix/addThrowAnnotation/js/");
}
@TestMetadata("jvm")
public void testJvm() throws Exception {
runTest("idea/testData/multiModuleQuickFix/addThrowAnnotation/jvm/");
}
@TestMetadata("jvmWithoutStdlib")
public void testJvmWithoutStdlib() throws Exception {
runTest("idea/testData/multiModuleQuickFix/addThrowAnnotation/jvmWithoutStdlib/");
}
}
@TestMetadata("idea/testData/multiModuleQuickFix/changeModifier") @TestMetadata("idea/testData/multiModuleQuickFix/changeModifier")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)