Do not offer to convert to infix call when calling non-infix function

This commit is contained in:
Valentin Kipyatkov
2015-10-09 18:41:10 +03:00
parent ee7425c1de
commit 55cbe185f8
30 changed files with 114 additions and 34 deletions
@@ -17,8 +17,11 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class ToInfixCallIntention : JetSelfTargetingIntention<JetCallExpression>(javaClass(), "Replace with infix function call") {
override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean {
@@ -33,9 +36,13 @@ public class ToInfixCallIntention : JetSelfTargetingIntention<JetCallExpression>
if (argument.isNamed()) return false
if (argument.getArgumentExpression() == null) return false
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = element.getResolvedCall(bindingContext) ?: return false
val function = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return false
if (!function.isInfix) return false
// check that receiver has type to filter out calls with package/java class qualifier
val receiver = dotQualified.getReceiverExpression()
if (element.analyze().getType(receiver) == null) return false
if (bindingContext.getType(dotQualified.receiverExpression) == null) return false
return true
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun compareTo(p: Int): Int
}
fun foo(x: X) {
x.<caret>compareTo(1 + 2)
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun compareTo(p: Int): Int
}
fun foo(x: X) {
x compareTo 1 + 2
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
x.tim<caret>es(1)
interface X {
infix fun infix(p: Int): X
}
fun foo(x: X) {
x.in<caret>fix(1)
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
x times 1
interface X {
infix fun infix(p: Int): X
}
fun foo(x: X) {
x infix 1
}
@@ -1,4 +1,8 @@
// IS_APPLICABLE: false
fun foo(num: Int) {
n<caret>um.times(1)
interface X {
infix fun infix(p: Int): X
}
fun foo(num: X) {
n<caret>um.infix(1)
}
+5 -1
View File
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun times(p: Int): Int
}
fun foo(x: X) {
(x.<caret>times(1)).div(2)
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun times(p: Int): Int
}
fun foo(x: X) {
(x times 1).div(2)
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun plus(p: Int): Int
}
fun foo(x: X) {
x.<caret>plus(1).minus(2)
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun plus(p: Int): Int
}
fun foo(x: X) {
(x plus 1).minus(2)
}
@@ -3,5 +3,5 @@ fun foo(x: Foo) {
}
interface Foo {
fun foo(f: (Int) -> Int)
infix fun foo(f: (Int) -> Int)
}
@@ -3,5 +3,5 @@ fun foo(x: Foo) {
}
interface Foo {
fun foo(f: (Int) -> Int)
infix fun foo(f: (Int) -> Int)
}
+3 -1
View File
@@ -1,4 +1,6 @@
// IS_APPLICABLE: false
fun String.xxx(p: String): Int = 0
fun foo(x: String?) {
x?.<caret>compareTo("1")
x?.<caret>xxx("1")
}
@@ -1,4 +1,6 @@
// IS_APPLICABLE: false
fun foo(x: Int) {
x.times(<caret>1)
fun String.xxx(p: Int): Int = 0
fun foo(x: String) {
x.xxx(<caret>1)
}
+2 -1
View File
@@ -1,6 +1,7 @@
// IS_APPLICABLE: false
// ERROR: 'infix' modifier is inapplicable on this function
interface Foo {
fun foo(a: Int, b: Int)
infix fun foo(a: Int, b: Int)
}
fun foo(x: Foo) {
+1 -1
View File
@@ -4,5 +4,5 @@ fun foo(x: Foo) {
}
interface Foo {
fun foo(baz: Int = 0, bar: Foo? = null)
infix fun foo(baz: Int = 0, bar: Foo? = null)
}
+6
View File
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
fun Int.xxx(p: Int) = 1
fun foo(x: Int) {
x.<caret>xxx(1)
}
@@ -1,3 +1,5 @@
infix fun String.xxx(p: Int): String = this
fun foo(x: String?) {
x!!.<caret>plus(1)
x!!.<caret>xxx(1)
}
@@ -1,3 +1,5 @@
infix fun String.xxx(p: Int): String = this
fun foo(x: String?) {
x!! plus 1
x!! xxx 1
}
@@ -1,5 +1,9 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
// ERROR: 'infix' modifier is inapplicable on this function
package ppp
infix fun foo(p: String){}
fun main() {
kotlin.io.<caret>println("")
ppp.<caret>foo("")
}
@@ -1,6 +1,6 @@
// IS_APPLICABLE: false
class Foo {
fun foo(x: Int = 0, y: Int = 0) {
infix fun foo(x: Int = 0, y: Int = 0) {
}
}
@@ -1,8 +1,10 @@
// IS_APPLICABLE: false
// ERROR: 'infix' modifier is inapplicable on this function
fun foo(x: Foo) {
x.<caret>foo(1) { it * 2 }
}
interface Foo {
fun foo(a: Int, f: (Int) -> Int)
infix fun foo(a: Int, f: (Int) -> Int)
}
+5 -1
View File
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun times(p: Int): Int
}
fun foo(x: X) {
x.<caret>times(1)
}
@@ -1,3 +1,7 @@
fun foo(x: Int) {
interface X {
infix fun times(p: Int): Int
}
fun foo(x: X) {
x times 1
}
@@ -1,8 +1,10 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// ERROR: 'infix' modifier is inapplicable on this function
package demo
fun foo(str: String) = kotlin.io.println(str)
infix fun foo(str: String) = kotlin.io.println(str)
fun main() {
<caret>demo.foo("")
+4 -1
View File
@@ -1,4 +1,7 @@
// IS_APPLICABLE: false
// ERROR: No value passed for parameter p
infix fun Int.xxx(p: Int) = 1
fun foo(x: Int) {
x.<caret>toString()
x.<caret>xxx()
}
@@ -1,6 +1,5 @@
// "Create class 'Foo'" "false"
// ACTION: Create extension function 'Foo'
// ACTION: Replace with infix function call
// ERROR: Unresolved reference: Foo
fun test() {
@@ -1,6 +1,5 @@
// "Create member function 'foo'" "false"
// ACTION: Convert to expression body
// ACTION: Replace with infix function call
// ERROR: Unresolved reference: x
class A<T>(val n: T) {
@@ -1,7 +1,6 @@
// "Create property 'foo'" "false"
// ACTION: Create extension function 'bar'
// ACTION: Create member function 'bar'
// ACTION: Replace with infix function call
// ERROR: Unresolved reference: bar
// ERROR: Unresolved reference: foo
@@ -7707,6 +7707,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("notInfix.kt")
public void testNotInfix() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/toInfixCall/notInfix.kt");
doTest(fileName);
}
@TestMetadata("nullAssertedReceiver.kt")
public void testNullAssertedReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/toInfixCall/nullAssertedReceiver.kt");