Intention for adding explicit type arguments at function calls

This commit is contained in:
Tal Man
2014-03-28 23:18:26 -04:00
committed by Andrey Breslav
parent f8db722011
commit cfc16b410e
38 changed files with 388 additions and 1 deletions
@@ -390,6 +390,7 @@ fun main(args: Array<String>) {
model("intentions/replaceWithOperatorAssign", testMethod = "doTestReplaceWithOperatorAssign")
model("intentions/replaceWithTraditionalAssignment", testMethod = "doTestReplaceWithTraditionalAssignment")
model("intentions/simplifyBooleanWithConstants", testMethod = "doTestSimplifyBooleanWithConstants")
model("intentions/insertExplicitTypeArguments", testMethod = "doTestInsertExplicitTypeArguments")
}
testClass(javaClass<AbstractJetInspectionTest>()) {
@@ -0,0 +1,5 @@
fun foo() {
<spot>bar<String>("x")</spot>
}
fun bar<T>(t: T) : T = t
@@ -0,0 +1,5 @@
fun foo() {
<spot>bar("x")</spot>
}
fun bar<T>(t: T) : T = t
@@ -0,0 +1,5 @@
<html>
<body>
This intention inserts explicit type arguments to function calls
</body>
</html>
+5
View File
@@ -568,6 +568,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.InsertExplicitTypeArguments</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.jet.plugin.intentions.MoveLambdaOutsideParenthesesIntention</className>
<category>Kotlin</category>
@@ -293,6 +293,9 @@ replace.with.traditional.assignment.intention=Replace with Traditional Assignmen
replace.with.traditional.assignment.intention.family=Replace with Traditional Assignment
simplify.boolean.with.constants=Simplify boolean expression
simplify.boolean.with.constants.family=Simplify boolean expression
insert.explicit.type.arguments=Add explicit type arguments
insert.explicit.type.arguments.family=Add explicit type arguments
>>>>>>> Intention for adding explicit type arguments at function calls
property.is.implemented.too.many=Has implementations
property.is.overridden.too.many=Is overridden in subclasses
@@ -0,0 +1,67 @@
/*
* Copyright 2010-2014 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.openapi.editor.Editor
import org.jetbrains.jet.lang.psi.JetCallExpression
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
import org.jetbrains.jet.lang.psi.JetPsiFactory
import kotlin.properties.Delegates
import org.jetbrains.jet.lang.types.TypeUtils
import org.jetbrains.jet.lang.types.ErrorUtils
import org.jetbrains.jet.renderer.DescriptorRenderer
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
public class InsertExplicitTypeArguments : JetSelfTargetingIntention<JetCallExpression>(
"insert.explicit.type.arguments", javaClass()) {
private var resolvedCall: ResolvedCall<out CallableDescriptor?> by Delegates.notNull()
override fun isApplicableTo(element: JetCallExpression): Boolean {
if (!element.getTypeArguments().isEmpty()) return false
val context = AnalyzerFacadeWithCache.getContextForElement(element)
val nullableResolvedCall = context[BindingContext.RESOLVED_CALL, element.getCalleeExpression()]
if (nullableResolvedCall == null) return false
resolvedCall = nullableResolvedCall
val types = resolvedCall.getTypeArguments()
return !types.isEmpty() && types.values().none { ErrorUtils.containsErrorType(it) }
}
override fun applyTo(element: JetCallExpression, editor: Editor) {
val args = resolvedCall.getTypeArguments()
val types = resolvedCall.getCandidateDescriptor()?.getTypeParameters()
if (types == null) return
val typeArgs = types.map {
assert(args[it] != null, "there is a null in the type arguments to transform")
val typeToCompute = DescriptorRenderer.TEXT.renderType(args[it]!!);
val computedTypeRef = JetPsiFactory.createType(element.getProject(), typeToCompute)
ShortenReferences.process(computedTypeRef)
computedTypeRef.getText()
}.makeString(", ", "<", ">")
val name = element.getCalleeExpression()?.getText()
val text = element.getText()
if (name == null || text == null) return
val valueAndFunctionArguments = text.substring(name.size)
val expr = JetPsiFactory.createExpression(element.getProject(), "$name$typeArgs${valueAndFunctionArguments}")
element.replace(expr)
}
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
fun foo() {
val x = <caret>bar<String>("x")
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
fun foo() {
val x = <caret>bar(1)
}
fun bar(t: Int): Int = 1
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
// ERROR: Unresolved reference: s
fun foo() {
val x = <caret>bar(s) // s not definded, can't be inferred
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val z = <caret>bar("1", 1, 2, "x")
}
fun bar<T, V, R, K>(t: T, v: V, r: R, k: K): Int = 2
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val z = <caret>bar<String, Int, Int, String>("1", 1, 2, "x")
}
fun bar<T, V, R, K>(t: T, v: V, r: R, k: K): Int = 2
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val z = <caret>bar("1", 1, 2, "x")
}
fun bar<R, K, T, V>(t: T, v: V, r: R, k: K): Int = 2
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val z = <caret>bar<Int, String, String, Int>("1", 1, 2, "x")
}
fun bar<R, K, T, V>(t: T, v: V, r: R, k: K): Int = 2
@@ -0,0 +1,10 @@
// IS_APPLICABLE: true
class Array
fun test() {
<caret>bar(foo(""), 0, foo(""))
}
fun foo(vararg x: String) = x
fun bar<T, R, V>(t: T, r: R, v: V) {}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: true
class Array
fun test() {
bar<kotlin.Array<String>, Int, kotlin.Array<String>>(foo(""), 0, foo(""))
}
fun foo(vararg x: String) = x
fun bar<T, R, V>(t: T, r: R, v: V) {}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val x = <caret>bar("x", 0)
}
fun bar<T, V>(t: T, v: V): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val x = bar<String, Int>("x", 0)
}
fun bar<T, V>(t: T, v: V): Int = 1
@@ -0,0 +1,8 @@
// IS_APPLICABLE: true
fun foo() {
val x = <caret>Box(Any())
}
class Box<T>(t : T) {
var value = t
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: true
fun foo() {
val x = Box<Any>(Any())
}
class Box<T>(t : T) {
var value = t
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
<caret>bar({ 2 * it }: (Int) -> Int)
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
bar<(Int) -> Int>({ 2 * it }: (Int) -> Int)
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo<T>(t: T) {
<caret>bar(t)
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo<T>(t: T) {
bar<T>(t)
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,10 @@
// IS_APPLICABLE: true
class Array
fun test() {
<caret>bar(foo(""))
}
fun foo(vararg x: String) = x
fun bar<T>(vararg ts: T) {}
@@ -0,0 +1,10 @@
// IS_APPLICABLE: true
class Array
fun test() {
bar<kotlin.Array<String>>(foo(""))
}
fun foo(vararg x: String) = x
fun bar<T>(vararg ts: T) {}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val z = <caret>bar { it * 2 }
}
fun bar<T>(a: (Int)->T): T = a(1)
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
val z = bar<Int> { it * 2 }
}
fun bar<T>(a: (Int)->T): T = a(1)
@@ -0,0 +1,8 @@
// IS_APPLICABLE: true
fun foo() {
val x = <caret>Box(Box("x"))
}
class Box<T>(t : T) {
var value = t
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: true
fun foo() {
val x = Box<Box<String>>(Box("x"))
}
class Box<T>(t : T) {
var value = t
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
<caret>bar(1, 2, 3, 4)
}
fun bar<T>(vararg ts: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
bar<Int>(1, 2, 3, 4)
}
fun bar<T>(vararg ts: T): Int = 1
@@ -0,0 +1,8 @@
// IS_APPLICABLE: true
fun foo() {
val x = <caret>Box("x")
}
class Box<T>(t : T) {
var value = t
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: true
fun foo() {
val x = Box<String>("x")
}
class Box<T>(t : T) {
var value = t
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
<caret>bar("x")
}
fun bar<T>(t: T): Int = 1
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
fun foo() {
bar<String>("x")
}
fun bar<T>(t: T): Int = 1
@@ -215,6 +215,10 @@ public abstract class AbstractCodeTransformationTest extends LightCodeInsightTes
doTestIntention(path, new SimplifyNegatedBinaryExpressionIntention());
}
public void doTestInsertExplicitTypeArguments(@NotNull String path) throws Exception {
doTestIntention(path, new InsertExplicitTypeArguments());
}
public void doTestSplitIf(@NotNull String path) throws Exception {
doTestIntention(path, new SplitIfIntention());
}
@@ -30,7 +30,7 @@ import org.jetbrains.jet.plugin.intentions.AbstractCodeTransformationTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@InnerTestClasses({CodeTransformationTestGenerated.ElvisToIfThen.class, CodeTransformationTestGenerated.IfThenToElvis.class, CodeTransformationTestGenerated.SafeAccessToIfThen.class, CodeTransformationTestGenerated.IfThenToSafeAccess.class, CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, CodeTransformationTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, CodeTransformationTestGenerated.RemoveBraces.class, CodeTransformationTestGenerated.AddBraces.class, CodeTransformationTestGenerated.ReplaceGetIntention.class, CodeTransformationTestGenerated.ReplaceContainsIntention.class, CodeTransformationTestGenerated.ReplaceBinaryInfixIntention.class, CodeTransformationTestGenerated.ReplaceUnaryPrefixIntention.class, CodeTransformationTestGenerated.ReplaceInvokeIntention.class, CodeTransformationTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, CodeTransformationTestGenerated.ConvertNegatedBooleanSequence.class, CodeTransformationTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, CodeTransformationTestGenerated.SwapBinaryExpression.class, CodeTransformationTestGenerated.SplitIf.class, CodeTransformationTestGenerated.ReplaceWithOperatorAssign.class, CodeTransformationTestGenerated.ReplaceWithTraditionalAssignment.class, CodeTransformationTestGenerated.SimplifyBooleanWithConstants.class})
@InnerTestClasses({CodeTransformationTestGenerated.ElvisToIfThen.class, CodeTransformationTestGenerated.IfThenToElvis.class, CodeTransformationTestGenerated.SafeAccessToIfThen.class, CodeTransformationTestGenerated.IfThenToSafeAccess.class, CodeTransformationTestGenerated.IfToAssignment.class, CodeTransformationTestGenerated.IfToReturn.class, CodeTransformationTestGenerated.IfToReturnAsymmetrically.class, CodeTransformationTestGenerated.WhenToAssignment.class, CodeTransformationTestGenerated.WhenToReturn.class, CodeTransformationTestGenerated.AssignmentToIf.class, CodeTransformationTestGenerated.AssignmentToWhen.class, CodeTransformationTestGenerated.PropertyToIf.class, CodeTransformationTestGenerated.PropertyToWhen.class, CodeTransformationTestGenerated.ReturnToIf.class, CodeTransformationTestGenerated.ReturnToWhen.class, CodeTransformationTestGenerated.IfToWhen.class, CodeTransformationTestGenerated.WhenToIf.class, CodeTransformationTestGenerated.Flatten.class, CodeTransformationTestGenerated.Merge.class, CodeTransformationTestGenerated.IntroduceSubject.class, CodeTransformationTestGenerated.EliminateSubject.class, CodeTransformationTestGenerated.Split.class, CodeTransformationTestGenerated.Join.class, CodeTransformationTestGenerated.ConvertMemberToExtension.class, CodeTransformationTestGenerated.ReconstructedType.class, CodeTransformationTestGenerated.RemoveUnnecessaryParentheses.class, CodeTransformationTestGenerated.ReplaceWithDotQualifiedMethodCall.class, CodeTransformationTestGenerated.ReplaceWithInfixFunctionCall.class, CodeTransformationTestGenerated.RemoveCurlyBracesFromTemplate.class, CodeTransformationTestGenerated.MoveLambdaInsideParentheses.class, CodeTransformationTestGenerated.MoveLambdaOutsideParentheses.class, CodeTransformationTestGenerated.ReplaceExplicitFunctionLiteralParamWithIt.class, CodeTransformationTestGenerated.ReplaceItWithExplicitFunctionLiteralParam.class, CodeTransformationTestGenerated.RemoveBraces.class, CodeTransformationTestGenerated.AddBraces.class, CodeTransformationTestGenerated.ReplaceGetIntention.class, CodeTransformationTestGenerated.ReplaceContainsIntention.class, CodeTransformationTestGenerated.ReplaceBinaryInfixIntention.class, CodeTransformationTestGenerated.ReplaceUnaryPrefixIntention.class, CodeTransformationTestGenerated.ReplaceInvokeIntention.class, CodeTransformationTestGenerated.SimplifyNegatedBinaryExpressionIntention.class, CodeTransformationTestGenerated.ConvertNegatedBooleanSequence.class, CodeTransformationTestGenerated.ConvertNegatedExpressionWithDemorgansLaw.class, CodeTransformationTestGenerated.SwapBinaryExpression.class, CodeTransformationTestGenerated.SplitIf.class, CodeTransformationTestGenerated.ReplaceWithOperatorAssign.class, CodeTransformationTestGenerated.ReplaceWithTraditionalAssignment.class, CodeTransformationTestGenerated.SimplifyBooleanWithConstants.class, CodeTransformationTestGenerated.InsertExplicitTypeArguments.class})
public class CodeTransformationTestGenerated extends AbstractCodeTransformationTest {
@TestMetadata("idea/testData/intentions/branched/elvisToIfThen")
public static class ElvisToIfThen extends AbstractCodeTransformationTest {
@@ -3327,6 +3327,94 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
}
@TestMetadata("idea/testData/intentions/insertExplicitTypeArguments")
public static class InsertExplicitTypeArguments extends AbstractCodeTransformationTest {
public void testAllFilesPresentInInsertExplicitTypeArguments() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/intentions/insertExplicitTypeArguments"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("inapplicableAlreadyTyped.kt")
public void testInapplicableAlreadyTyped() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/inapplicableAlreadyTyped.kt");
}
@TestMetadata("inapplicableNotGeneric.kt")
public void testInapplicableNotGeneric() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/inapplicableNotGeneric.kt");
}
@TestMetadata("inapplicableTypeNotInferred.kt")
public void testInapplicableTypeNotInferred() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/inapplicableTypeNotInferred.kt");
}
@TestMetadata("insertManyTypes.kt")
public void testInsertManyTypes() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertManyTypes.kt");
}
@TestMetadata("insertManyTypesInDifferentOrder.kt")
public void testInsertManyTypesInDifferentOrder() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertManyTypesInDifferentOrder.kt");
}
@TestMetadata("insertMultipleSomeWithClashingName.kt")
public void testInsertMultipleSomeWithClashingName() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertMultipleSomeWithClashingName.kt");
}
@TestMetadata("insertTwoTypesFun.kt")
public void testInsertTwoTypesFun() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTwoTypesFun.kt");
}
@TestMetadata("insertTypeAny.kt")
public void testInsertTypeAny() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeAny.kt");
}
@TestMetadata("insertTypeThatIsAFunction.kt")
public void testInsertTypeThatIsAFunction() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeThatIsAFunction.kt");
}
@TestMetadata("insertTypeThatIsATypeArg.kt")
public void testInsertTypeThatIsATypeArg() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeThatIsATypeArg.kt");
}
@TestMetadata("insertTypeWithClashingName.kt")
public void testInsertTypeWithClashingName() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeWithClashingName.kt");
}
@TestMetadata("insertTypeWithLambda.kt")
public void testInsertTypeWithLambda() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeWithLambda.kt");
}
@TestMetadata("insertTypeWithTypeArguments.kt")
public void testInsertTypeWithTypeArguments() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeWithTypeArguments.kt");
}
@TestMetadata("insertTypeWithVarargs.kt")
public void testInsertTypeWithVarargs() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/insertTypeWithVarargs.kt");
}
@TestMetadata("simpleInsertTypeClass.kt")
public void testSimpleInsertTypeClass() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/simpleInsertTypeClass.kt");
}
@TestMetadata("simpleInsertTypeFun.kt")
public void testSimpleInsertTypeFun() throws Exception {
doTestInsertExplicitTypeArguments("idea/testData/intentions/insertExplicitTypeArguments/simpleInsertTypeFun.kt");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("CodeTransformationTestGenerated");
suite.addTestSuite(ElvisToIfThen.class);
@@ -3377,6 +3465,7 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
suite.addTestSuite(ReplaceWithOperatorAssign.class);
suite.addTestSuite(ReplaceWithTraditionalAssignment.class);
suite.addTestSuite(SimplifyBooleanWithConstants.class);
suite.addTestSuite(InsertExplicitTypeArguments.class);
return suite;
}
}