diff --git a/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/after.kt.template
new file mode 100644
index 00000000000..09cb3823787
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/after.kt.template
@@ -0,0 +1,3 @@
+fun test(foo: dynamic) {
+ val s = foo as String
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/before.kt.template
new file mode 100644
index 00000000000..868847ec645
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/before.kt.template
@@ -0,0 +1,3 @@
+fun test(foo: dynamic) {
+ val s = foo.unsafeCast()
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/description.html b/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/description.html
new file mode 100644
index 00000000000..3ddb36a40a1
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ConvertUnsafeCastCallToUnsafeCastIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention converts unsafeCast() call to unsafe cast.
+
+
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/after.kt.template
new file mode 100644
index 00000000000..868847ec645
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/after.kt.template
@@ -0,0 +1,3 @@
+fun test(foo: dynamic) {
+ val s = foo.unsafeCast()
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/before.kt.template
new file mode 100644
index 00000000000..09cb3823787
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/before.kt.template
@@ -0,0 +1,3 @@
+fun test(foo: dynamic) {
+ val s = foo as String
+}
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/description.html b/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/description.html
new file mode 100644
index 00000000000..bfaf49288b6
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ConvertUnsafeCastToUnsafeCastCallIntention/description.html
@@ -0,0 +1,5 @@
+
+
+This intention converts unsafe cast to unsafeCast() call.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 816d5bee71e..c12a4526b73 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -1539,6 +1539,16 @@
Kotlin
+
+ org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastCallToUnsafeCastIntention
+ Kotlin
+
+
+
+ org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastToUnsafeCastCallIntention
+ Kotlin
+
+
(
+ KtDotQualifiedExpression::class.java, "Convert to unsafe cast"
+) {
+
+ override fun isApplicableTo(element: KtDotQualifiedExpression, caretOffset: Int): Boolean {
+ if (element.platform != JsPlatform) return false
+ if ((element.selectorExpression as? KtCallExpression)?.calleeExpression?.text != "unsafeCast") return false
+
+ val context = element.analyze(BodyResolveMode.PARTIAL)
+ val fqName = element.getResolvedCall(context)?.resultingDescriptor?.fqNameOrNull()?.asString() ?: return false
+ if (fqName != "kotlin.js.unsafeCast") return false
+
+ val type = element.callExpression?.typeArguments?.singleOrNull() ?: return false
+
+ text = "Convert to '${element.receiverExpression.text} as ${type.text}'"
+ return true
+ }
+
+ override fun applyTo(element: KtDotQualifiedExpression, editor: Editor?) {
+ val type = element.callExpression?.typeArguments?.singleOrNull() ?: return
+ val newExpression = KtPsiFactory(element).createExpressionByPattern("$0 as $1", element.receiverExpression, type.text)
+ element.replace(newExpression)
+ }
+
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertUnsafeCastToUnsafeCastCallIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertUnsafeCastToUnsafeCastCallIntention.kt
new file mode 100644
index 00000000000..d72c931fa88
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertUnsafeCastToUnsafeCastCallIntention.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o. 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.intentions
+
+import com.intellij.openapi.editor.Editor
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.project.platform
+import org.jetbrains.kotlin.js.resolve.JsPlatform
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.psi.createExpressionByPattern
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.types.TypeUtils
+
+class ConvertUnsafeCastToUnsafeCastCallIntention : SelfTargetingIntention(
+ KtBinaryExpressionWithTypeRHS::class.java, "Convert to unsafeCast() call"
+) {
+
+ override fun isApplicableTo(element: KtBinaryExpressionWithTypeRHS, caretOffset: Int): Boolean {
+ if (element.platform != JsPlatform) return false
+
+ if (element.operationReference.getReferencedNameElementType() != KtTokens.AS_KEYWORD) return false
+
+ val right = element.right ?: return false
+ val context = right.analyze(BodyResolveMode.PARTIAL)
+ val type = context[BindingContext.TYPE, right] ?: return false
+ if (TypeUtils.isNullableType(type)) return false
+
+ text = "Convert to '${element.left.text}.unsafeCast<${right.text}>()'"
+ return true
+ }
+
+ override fun applyTo(element: KtBinaryExpressionWithTypeRHS, editor: Editor?) {
+ val right = element.right ?: return
+ val newExpression = KtPsiFactory(element).createExpressionByPattern("$0.unsafeCast<$1>()", element.left, right)
+ element.replace(newExpression)
+ }
+
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/.intention b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/.intention
new file mode 100644
index 00000000000..c0ea104e0e2
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastCallToUnsafeCastIntention
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt
new file mode 100644
index 00000000000..dc412102c5f
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt
@@ -0,0 +1,4 @@
+// JS
+fun test(foo: dynamic) {
+ val s = foo.unsafeCast()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt.after b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt.after
new file mode 100644
index 00000000000..e496a5912f6
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt.after
@@ -0,0 +1,4 @@
+// JS
+fun test(foo: dynamic) {
+ val s = foo as String
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/safeCall.kt b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/safeCall.kt
new file mode 100644
index 00000000000..37068c95cc0
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/safeCall.kt
@@ -0,0 +1,5 @@
+// JS
+// IS_APPLICABLE: false
+fun test(foo: Any?) {
+ val s = foo?.unsafeCast()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/.intention b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/.intention
new file mode 100644
index 00000000000..3c151521e19
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/.intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.intentions.ConvertUnsafeCastToUnsafeCastCallIntention
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt
new file mode 100644
index 00000000000..e496a5912f6
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt
@@ -0,0 +1,4 @@
+// JS
+fun test(foo: dynamic) {
+ val s = foo as String
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt.after b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt.after
new file mode 100644
index 00000000000..dc412102c5f
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt.after
@@ -0,0 +1,4 @@
+// JS
+fun test(foo: dynamic) {
+ val s = foo.unsafeCast()
+}
\ No newline at end of file
diff --git a/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/safeCast.kt b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/safeCast.kt
new file mode 100644
index 00000000000..9444a2eb9d4
--- /dev/null
+++ b/idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/safeCast.kt
@@ -0,0 +1,5 @@
+// JS
+// IS_APPLICABLE: false
+fun test(foo: Any) {
+ val s = foo as? String
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
index 1c25acca029..08e4e7d94cc 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java
@@ -7141,6 +7141,48 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
+ @TestMetadata("idea/testData/intentions/convertUnsafeCastCallToUnsafeCast")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ConvertUnsafeCastCallToUnsafeCast extends AbstractIntentionTest {
+ public void testAllFilesPresentInConvertUnsafeCastCallToUnsafeCast() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertUnsafeCastCallToUnsafeCast"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("call.kt")
+ public void testCall() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/call.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("safeCall.kt")
+ public void testSafeCall() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertUnsafeCastCallToUnsafeCast/safeCall.kt");
+ doTest(fileName);
+ }
+ }
+
+ @TestMetadata("idea/testData/intentions/convertUnsafeCastToUnsafeCastCall")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ConvertUnsafeCastToUnsafeCastCall extends AbstractIntentionTest {
+ public void testAllFilesPresentInConvertUnsafeCastToUnsafeCastCall() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertUnsafeCastToUnsafeCastCall"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("cast.kt")
+ public void testCast() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/cast.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("safeCast.kt")
+ public void testSafeCast() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertUnsafeCastToUnsafeCastCall/safeCast.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/intentions/copyConcatenatedStringToClipboard")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)