diff --git a/generators/org/jetbrains/jet/generators/tests/GenerateTests.java b/generators/org/jetbrains/jet/generators/tests/GenerateTests.java
index 60f122de194..03953c2fb15 100644
--- a/generators/org/jetbrains/jet/generators/tests/GenerateTests.java
+++ b/generators/org/jetbrains/jet/generators/tests/GenerateTests.java
@@ -375,6 +375,7 @@ public class GenerateTests {
testModel("idea/testData/intentions/declarations/split", "doTestSplitProperty"),
testModel("idea/testData/intentions/declarations/join", "doTestJoinProperty"),
testModel("idea/testData/intentions/declarations/convertMemberToExtension", "doTestConvertMemberToExtension"),
+ testModel("idea/testData/intentions/reconstructedType", "doTestReconstructType"),
testModel("idea/testData/intentions/removeUnnecessaryParentheses", "doTestRemoveUnnecessaryParentheses")
);
diff --git a/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/after.kt.template b/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/after.kt.template
new file mode 100644
index 00000000000..fc5ee713e50
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/after.kt.template
@@ -0,0 +1 @@
+foo as Map
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/before.kt.template b/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/before.kt.template
new file mode 100644
index 00000000000..e328ad61a68
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/before.kt.template
@@ -0,0 +1 @@
+foo as Map
\ No newline at end of file
diff --git a/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/description.html b/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/description.html
new file mode 100644
index 00000000000..a1acebdebde
--- /dev/null
+++ b/idea/resources/intentionDescriptions/ReconstructTypeInCastOrIsAction/description.html
@@ -0,0 +1,5 @@
+
+
+This intention replaces a shortened type on the right-hand side of as/as?/is/!is by its complete version
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 8d7726e87b8..e0d75a22dfb 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -426,6 +426,11 @@
Kotlin
+
+ org.jetbrains.jet.plugin.intentions.ReconstructTypeInCastOrIsAction
+ Kotlin
+
+
diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties
index ebf7126a735..da67c03c6c3 100644
--- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties
+++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties
@@ -276,4 +276,6 @@ find.what.constructor.usages.checkbox=Usages of &constructor
find.what.derived.traits.checkbox=&Derived traits
find.what.derived.classes.checkbox=&Derived classes
-convert.to.extension=Convert to extension
\ No newline at end of file
+convert.to.extension=Convert to extension
+replace.by.reconstructed.type.family.name=Replace by Reconstructed Type
+replace.by.reconstructed.type=Replace by ''{0}''
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/jet/plugin/intentions/ReconstructTypeInCastOrIsAction.java b/idea/src/org/jetbrains/jet/plugin/intentions/ReconstructTypeInCastOrIsAction.java
new file mode 100644
index 00000000000..ae4c5d793fa
--- /dev/null
+++ b/idea/src/org/jetbrains/jet/plugin/intentions/ReconstructTypeInCastOrIsAction.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2010-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.jet.plugin.intentions;
+
+import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jet.lang.psi.*;
+import org.jetbrains.jet.lang.resolve.BindingContext;
+import org.jetbrains.jet.lang.types.ErrorUtils;
+import org.jetbrains.jet.lang.types.JetType;
+import org.jetbrains.jet.plugin.JetBundle;
+import org.jetbrains.jet.plugin.codeInsight.ReferenceToClassesShortening;
+import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
+import org.jetbrains.jet.renderer.DescriptorRenderer;
+
+import java.util.Collections;
+
+public class ReconstructTypeInCastOrIsAction extends PsiElementBaseIntentionAction {
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return JetBundle.message("replace.by.reconstructed.type.family.name");
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
+ JetTypeReference typeRef = PsiTreeUtil.getTopmostParentOfType(element, JetTypeReference.class);
+ assert typeRef != null : "Must be checked by isAvailable(): " + element;
+
+ JetType type = getReconstructedType(typeRef);
+ JetTypeReference newType = JetPsiFactory.createType(project, DescriptorRenderer.SOURCE_CODE.renderType(type));
+ JetTypeReference replaced = (JetTypeReference) typeRef.replace(newType);
+ ReferenceToClassesShortening.compactReferenceToClasses(Collections.singletonList(replaced));
+ }
+
+ @Override
+ public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
+ JetTypeReference typeRef = PsiTreeUtil.getTopmostParentOfType(element, JetTypeReference.class);
+ if (typeRef == null) return false;
+
+ // Only user types (like Foo) are interesting
+ JetTypeElement typeElement = typeRef.getTypeElement();
+ if (!(typeElement instanceof JetUserType)) return false;
+
+ // If there are generic arguments already, there's nothing to reconstruct
+ if (!((JetUserType) typeElement).getTypeArguments().isEmpty()) return false;
+
+ // We must be on the RHS of as/as?/is/!is or inside an is/!is-condition in when()
+ JetExpression outerExpression = PsiTreeUtil.getParentOfType(typeRef, JetExpression.class);
+ if (!(outerExpression instanceof JetBinaryExpressionWithTypeRHS)) {
+ JetWhenConditionIsPattern outerIsCondition = PsiTreeUtil.getParentOfType(typeRef, JetWhenConditionIsPattern.class);
+ if (outerIsCondition == null) return false;
+ }
+
+ JetType type = getReconstructedType(typeRef);
+ if (type == null) return false;
+ if (ErrorUtils.isErrorType(type)) return false;
+
+ // No type parameters expected => nothing to reconstruct
+ if (type.getConstructor().getParameters().isEmpty()) return false;
+
+ setText(JetBundle.message("replace.by.reconstructed.type", type));
+
+ return true;
+ }
+
+ private static JetType getReconstructedType(JetTypeReference typeRef) {
+ BindingContext bindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) typeRef.getContainingFile()).getBindingContext();
+ return bindingContext.get(BindingContext.TYPE, typeRef);
+ }
+}
diff --git a/idea/testData/intentions/reconstructedType/completeGenericType.kt b/idea/testData/intentions/reconstructedType/completeGenericType.kt
new file mode 100644
index 00000000000..5169032f1af
--- /dev/null
+++ b/idea/testData/intentions/reconstructedType/completeGenericType.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+class G
+
+fun foo(a: Any) = a as G<*>
\ No newline at end of file
diff --git a/idea/testData/intentions/reconstructedType/completeType.kt b/idea/testData/intentions/reconstructedType/completeType.kt
new file mode 100644
index 00000000000..9cf04bfcdf4
--- /dev/null
+++ b/idea/testData/intentions/reconstructedType/completeType.kt
@@ -0,0 +1,4 @@
+// IS_APPLICABLE: false
+class G
+
+fun foo(a: Any) = a as G
\ No newline at end of file
diff --git a/idea/testData/intentions/reconstructedType/errorType.kt b/idea/testData/intentions/reconstructedType/errorType.kt
new file mode 100644
index 00000000000..6e2deb6e00c
--- /dev/null
+++ b/idea/testData/intentions/reconstructedType/errorType.kt
@@ -0,0 +1,2 @@
+// IS_APPLICABLE: false
+fun foo(a: Any) = a as G
\ No newline at end of file
diff --git a/idea/testData/intentions/reconstructedType/reconstructableType.kt b/idea/testData/intentions/reconstructedType/reconstructableType.kt
new file mode 100644
index 00000000000..fdc206ab427
--- /dev/null
+++ b/idea/testData/intentions/reconstructedType/reconstructableType.kt
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: true
+class B
+class G: B
+
+fun foo(a: B) = a as G
\ No newline at end of file
diff --git a/idea/testData/intentions/reconstructedType/reconstructableType.kt.after b/idea/testData/intentions/reconstructedType/reconstructableType.kt.after
new file mode 100644
index 00000000000..43667449d20
--- /dev/null
+++ b/idea/testData/intentions/reconstructedType/reconstructableType.kt.after
@@ -0,0 +1,5 @@
+// IS_APPLICABLE: true
+class B
+class G: B
+
+fun foo(a: B) = a as G
\ No newline at end of file
diff --git a/idea/testData/intentions/reconstructedType/typeInDeclaration.kt b/idea/testData/intentions/reconstructedType/typeInDeclaration.kt
new file mode 100644
index 00000000000..0dccfec39ff
--- /dev/null
+++ b/idea/testData/intentions/reconstructedType/typeInDeclaration.kt
@@ -0,0 +1,2 @@
+// IS_APPLICABLE: false
+fun foo(a: Any) = 1
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java
index dd61009c664..e5aee15a1fe 100644
--- a/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java
+++ b/idea/tests/org/jetbrains/jet/plugin/intentions/AbstractCodeTransformationTest.java
@@ -110,6 +110,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes
doTestIntention(path, new ConvertMemberToExtension());
}
+ public void doTestReconstructType(@NotNull String path) throws Exception {
+ doTestIntention(path, new ReconstructTypeInCastOrIsAction());
+ }
+
private void doTestIntention(@NotNull String path, @NotNull IntentionAction intentionAction) throws Exception {
configureByFile(path);
diff --git a/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java
index 60c0a9116ea..615bdf7c68c 100644
--- a/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java
+++ b/idea/tests/org/jetbrains/jet/plugin/intentions/CodeTransformationsTestGenerated.java
@@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.intentions.AbstractCodeTransformationTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
-@InnerTestClasses({CodeTransformationsTestGenerated.IfToAssignment.class, CodeTransformationsTestGenerated.IfToReturn.class, CodeTransformationsTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationsTestGenerated.WhenToAssignment.class, CodeTransformationsTestGenerated.WhenToReturn.class, CodeTransformationsTestGenerated.AssignmentToIf.class, CodeTransformationsTestGenerated.AssignmentToWhen.class, CodeTransformationsTestGenerated.PropertyToIf.class, CodeTransformationsTestGenerated.PropertyToWhen.class, CodeTransformationsTestGenerated.ReturnToIf.class, CodeTransformationsTestGenerated.ReturnToWhen.class, CodeTransformationsTestGenerated.IfToWhen.class, CodeTransformationsTestGenerated.WhenToIf.class, CodeTransformationsTestGenerated.Flatten.class, CodeTransformationsTestGenerated.IntroduceSubject.class, CodeTransformationsTestGenerated.EliminateSubject.class, CodeTransformationsTestGenerated.Split.class, CodeTransformationsTestGenerated.Join.class, CodeTransformationsTestGenerated.ConvertMemberToExtension.class, CodeTransformationsTestGenerated.RemoveUnnecessaryParentheses.class})
+@InnerTestClasses({CodeTransformationsTestGenerated.IfToAssignment.class, CodeTransformationsTestGenerated.IfToReturn.class, CodeTransformationsTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationsTestGenerated.WhenToAssignment.class, CodeTransformationsTestGenerated.WhenToReturn.class, CodeTransformationsTestGenerated.AssignmentToIf.class, CodeTransformationsTestGenerated.AssignmentToWhen.class, CodeTransformationsTestGenerated.PropertyToIf.class, CodeTransformationsTestGenerated.PropertyToWhen.class, CodeTransformationsTestGenerated.ReturnToIf.class, CodeTransformationsTestGenerated.ReturnToWhen.class, CodeTransformationsTestGenerated.IfToWhen.class, CodeTransformationsTestGenerated.WhenToIf.class, CodeTransformationsTestGenerated.Flatten.class, CodeTransformationsTestGenerated.IntroduceSubject.class, CodeTransformationsTestGenerated.EliminateSubject.class, CodeTransformationsTestGenerated.Split.class, CodeTransformationsTestGenerated.Join.class, CodeTransformationsTestGenerated.ConvertMemberToExtension.class, CodeTransformationsTestGenerated.ReconstructedType.class, CodeTransformationsTestGenerated.RemoveUnnecessaryParentheses.class})
public class CodeTransformationsTestGenerated extends AbstractCodeTransformationTest {
@TestMetadata("idea/testData/intentions/branched/folding/ifToAssignment")
public static class IfToAssignment extends AbstractCodeTransformationTest {
@@ -974,6 +974,39 @@ public class CodeTransformationsTestGenerated extends AbstractCodeTransformation
}
+ @TestMetadata("idea/testData/intentions/reconstructedType")
+ public static class ReconstructedType extends AbstractCodeTransformationTest {
+ public void testAllFilesPresentInReconstructedType() throws Exception {
+ JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/intentions/reconstructedType"), Pattern.compile("^(.+)\\.kt$"), true);
+ }
+
+ @TestMetadata("completeGenericType.kt")
+ public void testCompleteGenericType() throws Exception {
+ doTestReconstructType("idea/testData/intentions/reconstructedType/completeGenericType.kt");
+ }
+
+ @TestMetadata("completeType.kt")
+ public void testCompleteType() throws Exception {
+ doTestReconstructType("idea/testData/intentions/reconstructedType/completeType.kt");
+ }
+
+ @TestMetadata("errorType.kt")
+ public void testErrorType() throws Exception {
+ doTestReconstructType("idea/testData/intentions/reconstructedType/errorType.kt");
+ }
+
+ @TestMetadata("reconstructableType.kt")
+ public void testReconstructableType() throws Exception {
+ doTestReconstructType("idea/testData/intentions/reconstructedType/reconstructableType.kt");
+ }
+
+ @TestMetadata("typeInDeclaration.kt")
+ public void testTypeInDeclaration() throws Exception {
+ doTestReconstructType("idea/testData/intentions/reconstructedType/typeInDeclaration.kt");
+ }
+
+ }
+
@TestMetadata("idea/testData/intentions/removeUnnecessaryParentheses")
public static class RemoveUnnecessaryParentheses extends AbstractCodeTransformationTest {
public void testAllFilesPresentInRemoveUnnecessaryParentheses() throws Exception {
@@ -1063,6 +1096,7 @@ public class CodeTransformationsTestGenerated extends AbstractCodeTransformation
suite.addTestSuite(Split.class);
suite.addTestSuite(Join.class);
suite.addTestSuite(ConvertMemberToExtension.class);
+ suite.addTestSuite(ReconstructedType.class);
suite.addTestSuite(RemoveUnnecessaryParentheses.class);
return suite;
}