Add quickfix for UnsafeCastFromDynamicInspection #KT-20915 Fixed

This commit is contained in:
Toshiaki Kameyama
2017-12-08 19:53:16 +09:00
committed by Alexey Sedunov
parent f709a382ae
commit 113e9f496e
9 changed files with 87 additions and 4 deletions
@@ -5,14 +5,15 @@
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.expressionVisitor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.isDynamic
@@ -24,8 +25,26 @@ class UnsafeCastFromDynamicInspection : AbstractKotlinInspection() {
val actualType = expression.getType(context) ?: return
if (actualType.isDynamic() && !expectedType.isDynamic() && !TypeUtils.noExpectedType(expectedType)) {
holder.registerProblem(expression, "Implicit (unsafe) cast from dynamic to $expectedType")
holder.registerProblem(
expression,
"Implicit (unsafe) cast from dynamic to $expectedType",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
CastExplicitlyFix(expectedType))
}
})
}
}
private class CastExplicitlyFix(private val type: KotlinType) : LocalQuickFix {
override fun getName() = "Cast explicitly"
override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val expression = descriptor.psiElement as? KtExpression ?: return
val typeName = type.constructor.declarationDescriptor?.name ?: return
val pattern = if (type.isMarkedNullable) "$0 as? $1" else "$0 as $1"
val newExpression = KtPsiFactory(expression).createExpressionByPattern(pattern, expression, typeName)
expression.replace(newExpression)
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.inspections.UnsafeCastFromDynamicInspection
@@ -0,0 +1,6 @@
// JS
fun test() {
val d: dynamic = Any()
var i: Int = 0
i = <caret>d + d
}
@@ -0,0 +1,6 @@
// JS
fun test() {
val d: dynamic = Any()
var i: Int = 0
i = (d + d) as Int
}
@@ -0,0 +1,6 @@
// JS
fun test() {
val d: dynamic = Any()
var s: String? = null
s = <caret>d
}
@@ -0,0 +1,6 @@
// JS
fun test() {
val d: dynamic = Any()
var s: String? = null
s = d as? String
}
@@ -0,0 +1,6 @@
// JS
fun test() {
val d: dynamic = Any()
var s: String = ""
s = <caret>d
}
@@ -0,0 +1,6 @@
// JS
fun test() {
val d: dynamic = Any()
var s: String = ""
s = d as String
}
@@ -4081,6 +4081,33 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/unsafeCastFromDynamic")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class UnsafeCastFromDynamic extends AbstractLocalInspectionTest {
public void testAllFilesPresentInUnsafeCastFromDynamic() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/unsafeCastFromDynamic"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("binaryExpression.kt")
public void testBinaryExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/unsafeCastFromDynamic/binaryExpression.kt");
doTest(fileName);
}
@TestMetadata("nullable.kt")
public void testNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/unsafeCastFromDynamic/nullable.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/unsafeCastFromDynamic/simple.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/inspectionsLocal/unusedReceiverParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)