FIR: Fix false positive INAPPLICABLE_INFIX_MODIFIER
This commit is contained in:
+12
-1
@@ -10,4 +10,15 @@ infix class A
|
|||||||
|
|
||||||
infix typealias B = 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 typealias B = R|A|
|
||||||
public final val x: R|kotlin/Int| = Int(1)
|
public final val x: R|kotlin/Int| = Int(1)
|
||||||
public get(): R|kotlin/Int|
|
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> {
|
interface List<out T : Any> {
|
||||||
operator fun get(index: Int): T
|
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>
|
typealias StringList = List<out String>
|
||||||
|
|||||||
+11
-2
@@ -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.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
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.FirMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.isInfix
|
import org.jetbrains.kotlin.fir.declarations.isInfix
|
||||||
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.fir.declarations.isInfix
|
|||||||
object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDeclaration>() {
|
object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDeclaration>() {
|
||||||
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (declaration is FirSimpleFunction && declaration.isInfix) {
|
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)
|
reporter.report(declaration.source)
|
||||||
}
|
}
|
||||||
return
|
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?) {
|
private fun DiagnosticReporter.report(source: FirSourceElement?) {
|
||||||
source?.let { report(FirErrors.INAPPLICABLE_INFIX_MODIFIER.on(it, "Inapplicable infix modifier")) }
|
source?.let { report(FirErrors.INAPPLICABLE_INFIX_MODIFIER.on(it, "Inapplicable infix modifier")) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,5 +29,5 @@ infix fun String.on(predicate : (s : URI) -> Boolean) : URI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class URI(val body : Any) {
|
class URI(val body : Any) {
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun to(dest : String) {}<!>
|
infix fun to(dest : String) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
class Pair<out A, out B>(val first: A, val second: B)
|
class Pair<out A, out B>(val first: A, val second: B)
|
||||||
|
|
||||||
class Example {
|
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)
|
fun toNonInfix(other: Example) = Pair(this, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,4 +35,4 @@ fun test() {
|
|||||||
a toExtNonInfixDefaultValues b
|
a toExtNonInfixDefaultValues b
|
||||||
|
|
||||||
a withLambda { }
|
a withLambda { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
|
|||||||
// OK
|
// OK
|
||||||
infix fun String.ok1(o: String) {}
|
infix fun String.ok1(o: String) {}
|
||||||
class OkTest {
|
class OkTest {
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun ok2(o: String) {}<!>
|
infix fun ok2(o: String) {}
|
||||||
infix fun String.ok3(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 e8(s: String, a: Int = 0) {}<!>
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e9(s: String, a: Int) {}<!>
|
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e9(s: String, a: Int) {}<!>
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e10() {}<!>
|
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun e10() {}<!>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ interface Example {
|
|||||||
operator fun hasNext(): Boolean
|
operator fun hasNext(): Boolean
|
||||||
operator fun hasNext(n: Int): String
|
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(n: Int, n2: Int)<!>
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun i1(vararg n: Int)<!>
|
infix fun i1(vararg n: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
class OkDelegates {
|
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
|
//KT-4529 Lambdas are analyzed improperly in an infix call nested inside a println
|
||||||
|
|
||||||
class G {
|
class G {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -4,7 +4,7 @@ interface Foo
|
|||||||
fun (Foo.() -> Unit).invoke(b : Foo.() -> Unit) {}
|
fun (Foo.() -> Unit).invoke(b : Foo.() -> Unit) {}
|
||||||
|
|
||||||
object Z {
|
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<!> { } { }
|
val t2 = Z <!INAPPLICABLE_CANDIDATE!>add<!> { } { }
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -NOTHING_TO_INLINE
|
||||||
|
|
||||||
class Z {
|
class Z {
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>inline infix fun <R> inlineFun(crossinline p: () -> R) {
|
inline infix fun <R> inlineFun(crossinline p: () -> R) {
|
||||||
p()
|
p()
|
||||||
}<!>
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <R> fun1(p: () -> R) {
|
fun <R> fun1(p: () -> R) {
|
||||||
|
|||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER, -EXTENSION_SHADOWED_BY_MEMBER
|
||||||
|
|
||||||
class Example {
|
class Example {
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>operator infix fun plus(other: Example) = 0<!>
|
operator infix fun plus(other: Example) = 0
|
||||||
fun minus(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
|
fun div(other: Example) = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,4 +42,4 @@ fun a() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun consumeInt(i: Int) {}
|
fun consumeInt(i: Int) {}
|
||||||
fun consumeString(s: String) {}
|
fun consumeString(s: String) {}
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
// !WITH_NEW_INFERENCE
|
||||||
class A() {
|
class A() {
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>operator infix fun plus(i : Int) {}<!>
|
operator infix fun plus(i : Int) {}
|
||||||
operator fun unaryMinus() {}
|
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) {}
|
operator infix fun A.div(i : Int) {}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
interface IFoo {
|
interface IFoo {
|
||||||
fun foo(i: Int): Int
|
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.foo(i: Int) = i
|
||||||
infix fun IFoo.bar(i: Int) = i
|
infix fun IFoo.bar(i: Int) = i
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package o
|
package o
|
||||||
|
|
||||||
class A {
|
class A {
|
||||||
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun foo(b: B) = b<!>
|
infix fun foo(b: B) = b
|
||||||
}
|
}
|
||||||
|
|
||||||
class B {
|
class B {
|
||||||
@@ -11,4 +11,4 @@ class B {
|
|||||||
fun test(a: A, b: B?) {
|
fun test(a: A, b: B?) {
|
||||||
a foo b!!
|
a foo b!!
|
||||||
b.bar()
|
b.bar()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user