FIR: Fix false positive INAPPLICABLE_INFIX_MODIFIER

This commit is contained in:
Denis Zharkov
2020-04-20 15:29:14 +03:00
parent 27b860682b
commit fa3b3e7a9a
16 changed files with 65 additions and 42 deletions
@@ -10,4 +10,15 @@ infix class A
infix typealias B = A
infix val x = 1
infix val x = 1
class C {
infix fun good(x: Int) {}
infix fun Int.goodAsWell(x: Int) {}
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun Int.foo(x: Int, y: Int) {}<!>
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun Int.bar() {}<!>
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun baz(x: Int, y: Int) {}<!>
}
@@ -16,3 +16,24 @@ FILE: infixFunctions.kt
public final typealias B = R|A|
public final val x: R|kotlin/Int| = Int(1)
public get(): R|kotlin/Int|
public final class C : R|kotlin/Any| {
public constructor(): R|C| {
super<R|kotlin/Any|>()
}
public final infix fun good(x: R|kotlin/Int|): R|kotlin/Unit| {
}
public final infix fun R|kotlin/Int|.goodAsWell(x: R|kotlin/Int|): R|kotlin/Unit| {
}
public final infix fun R|kotlin/Int|.foo(x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Unit| {
}
public final infix fun R|kotlin/Int|.bar(): R|kotlin/Unit| {
}
public final infix fun baz(x: R|kotlin/Int|, y: R|kotlin/Int|): R|kotlin/Unit| {
}
}
@@ -1,7 +1,7 @@
interface List<out T : Any> {
operator fun get(index: Int): T
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun concat(other: List<T>): List<T><!>
infix fun concat(other: List<T>): List<T>
}
typealias StringList = List<out String>
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.isInfix
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.fir.declarations.isInfix
object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDeclaration>() {
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirSimpleFunction && declaration.isInfix) {
if (declaration.valueParameters.size != 1 || declaration.receiverTypeRef == null) {
if (declaration.valueParameters.size != 1 || !hasExtensionOrDispatchReceiver(declaration, context)) {
reporter.report(declaration.source)
}
return
@@ -26,7 +27,15 @@ object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDecla
}
}
private fun hasExtensionOrDispatchReceiver(
function: FirSimpleFunction,
context: CheckerContext
): Boolean {
if (function.receiverTypeRef != null) return true
return context.containingDeclarations.lastOrNull() is FirClass<*>
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(FirErrors.INAPPLICABLE_INFIX_MODIFIER.on(it, "Inapplicable infix modifier")) }
}
}
}
+1 -1
View File
@@ -29,5 +29,5 @@ infix fun String.on(predicate : (s : URI) -> Boolean) : URI {
}
class URI(val body : Any) {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun to(dest : String) {}<!>
infix fun to(dest : String) {}
}
+2 -2
View File
@@ -1,7 +1,7 @@
class Pair<out A, out B>(val first: A, val second: B)
class Example {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun to(other: Example) = Pair(this, other)<!>
infix fun to(other: Example) = Pair(this, other)
fun toNonInfix(other: Example) = Pair(this, other)
}
@@ -35,4 +35,4 @@ fun test() {
a toExtNonInfixDefaultValues b
a withLambda { }
}
}
@@ -6,7 +6,7 @@ infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
// OK
infix fun String.ok1(o: String) {}
class OkTest {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun ok2(o: String) {}<!>
infix fun ok2(o: String) {}
infix fun String.ok3(o: String) {}
}
@@ -24,4 +24,4 @@ class Example {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e8(s: String, a: Int = 0) {}<!>
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e9(s: String, a: Int) {}<!>
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e10() {}<!>
}
}
+2 -2
View File
@@ -59,9 +59,9 @@ interface Example {
operator fun hasNext(): Boolean
operator fun hasNext(n: Int): String
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun i1(n: Int)<!>
infix fun i1(n: Int)
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun i1(n: Int, n2: Int)<!>
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun i1(vararg n: Int)<!>
infix fun i1(vararg n: Int)
}
class OkDelegates {
@@ -1,19 +0,0 @@
//KT-4529 Lambdas are analyzed improperly in an infix call nested inside a println
class G {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun foo(bar: (Int) -> Int) = bar<!>
}
fun main() {
use(
G().foo {it + 11} // no error
)
use(
G() foo {it + 11} // ERROR
)
use(
G() foo ({it + 1}) // 2 ERRORs
)
}
fun use(a: Any?) = a
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
//KT-4529 Lambdas are analyzed improperly in an infix call nested inside a println
class G {
@@ -4,7 +4,7 @@ interface Foo
fun (Foo.() -> Unit).invoke(b : Foo.() -> Unit) {}
object Z {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun add(b : Foo.() -> Unit) : Z = Z<!>
infix fun add(b : Foo.() -> Unit) : Z = Z
}
val t2 = Z <!INAPPLICABLE_CANDIDATE!>add<!> { } { }
@@ -1,9 +1,9 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
class Z {
<!INAPPLICABLE_INFIX_MODIFIER!>inline infix fun <R> inlineFun(crossinline p: () -> R) {
inline infix fun <R> inlineFun(crossinline p: () -> R) {
p()
}<!>
}
}
fun <R> fun1(p: () -> R) {
@@ -1,10 +1,10 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER
class Example {
<!INAPPLICABLE_INFIX_MODIFIER!>operator infix fun plus(other: Example) = 0<!>
operator infix fun plus(other: Example) = 0
fun minus(other: Example) = 0
<!INAPPLICABLE_INFIX_MODIFIER!>operator infix fun times(other: Example) = 0<!>
operator infix fun times(other: Example) = 0
fun div(other: Example) = 0
}
@@ -42,4 +42,4 @@ fun a() {
}
fun consumeInt(i: Int) {}
fun consumeString(s: String) {}
fun consumeString(s: String) {}
@@ -1,8 +1,8 @@
// !WITH_NEW_INFERENCE
class A() {
<!INAPPLICABLE_INFIX_MODIFIER!>operator infix fun plus(i : Int) {}<!>
operator infix fun plus(i : Int) {}
operator fun unaryMinus() {}
<!INAPPLICABLE_INFIX_MODIFIER!>operator infix fun contains(a : Any?) : Boolean = true<!>
operator infix fun contains(a : Any?) : Boolean = true
}
operator infix fun A.div(i : Int) {}
@@ -1,7 +1,7 @@
interface IFoo {
fun foo(i: Int): Int
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun bar(i: Int): Int<!>
infix fun bar(i: Int): Int
}
infix fun IFoo.foo(i: Int) = i
infix fun IFoo.bar(i: Int) = i
infix fun IFoo.bar(i: Int) = i
@@ -1,7 +1,7 @@
package o
class A {
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun foo(b: B) = b<!>
infix fun foo(b: B) = b
}
class B {
@@ -11,4 +11,4 @@ class B {
fun test(a: A, b: B?) {
a foo b!!
b.bar()
}
}