FIR: pass the qualified access source when reporting ErrorNamedReference

Currently if there is an error in a function call, FIR would report the
entire expression if this call is qualified, but *only* the name if it's
not qualified. For example, assume the following two calls are all
contains some errors.

```
a.foo(1,2,3)
^^^^^^^^^^^^
bar(1,2,3)
^^^
```

The entire call of `foo` is reported since it's qualified. But only the
reference `bar` is reported since it's not qualified. This limits the
usage of position strategies because the IDE does not allow position
strategies to go outside of the initially reported PSI element
(org.jetbrains.kotlin.idea.fir.highlighter.KotlinHighLevelDiagnosticHighlightingPass#addDiagnostic).

This change passes both the original error named reference and the
surrounding qualified access expression and defer the decision of which
to use to the reporting logic.

For unresolved reference and checks on `super` keyword, the position
strategy should not highlight the surrounding parentheses. Hence a new
position strategy `REFERENCED_NAME_BY_QUALIFIED` is added.

In addition, this change also has the following side effect

* some diagnostics are no longer reported when there is a syntax error
  since the higher level structure does not exist when there is a syntax
  error
This commit is contained in:
Tianyu Geng
2021-03-07 16:10:29 -08:00
committed by Dmitriy Novozhilov
parent 8805675539
commit d6907222cd
53 changed files with 247 additions and 155 deletions
@@ -9,7 +9,7 @@ fun f(): Unit {
x <!NONE_APPLICABLE!>+<!> 1
x <!NONE_APPLICABLE!>plus<!> 1
x <!NONE_APPLICABLE!><<!> 1
<!UNRESOLVED_REFERENCE!>x += 1<!>
x <!UNRESOLVED_REFERENCE!>+=<!> 1
x == 1
x != 1
@@ -28,20 +28,20 @@ fun <T> fooT2() : (t : T) -> T {
fun main(args : Array<String>) {
args.foo()()
args.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
<!UNRESOLVED_REFERENCE!>a<!>.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
<!INAPPLICABLE_CANDIDATE!>args.foo1()<!>()
<!INAPPLICABLE_CANDIDATE!><!UNRESOLVED_REFERENCE!>a<!>.foo1()<!>()
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
args.foo1()(1)
args.<!INAPPLICABLE_CANDIDATE!>foo1<!>()("1")
<!UNRESOLVED_REFERENCE!>a<!>.<!INAPPLICABLE_CANDIDATE!>foo1<!>()("1")
<!INAPPLICABLE_CANDIDATE!>args.foo1()<!>("1")
<!INAPPLICABLE_CANDIDATE!><!UNRESOLVED_REFERENCE!>a<!>.foo1()<!>("1")
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
foo2()({})
<!INAPPLICABLE_CANDIDATE!>foo2<!>(){}
(foo2()){}
<!INAPPLICABLE_CANDIDATE!>(foo2())<!>{x -> }
<!INAPPLICABLE_CANDIDATE!>foo2<!>()({x -> })
<!INAPPLICABLE_CANDIDATE!>foo2()<!>({x -> })
val a = fooT1(1)()
checkSubtype<Int>(a)
@@ -58,13 +58,13 @@ fun main(args : Array<String>) {
fun f() : Int.() -> Unit = {}
fun main1() {
1.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>();
1.(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)();
{1}();
(fun (x : Int) = x)(1)
1.<!UNRESOLVED_REFERENCE!>(fun Int.(x : Int) = x)<!>(1);
1.(<!UNRESOLVED_REFERENCE!>fun Int.(x : Int) = x<!>)(1);
l@{1}()
1.<!UNRESOLVED_REFERENCE!>((fun Int.() = 1))<!>()
1.<!UNRESOLVED_REFERENCE!>(f())<!>()
1.((<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>))()
1.(<!UNRESOLVED_REFERENCE!>f()<!>)()
1.<!UNRESOLVED_REFERENCE!>if(true){f()}else{f()}<!>()
1.<!UNRESOLVED_REFERENCE!>if(true)(fun Int.() {})else{f()}<!>()
@@ -78,10 +78,10 @@ fun main1() {
fun test() {
<!INAPPLICABLE_CANDIDATE!>{x : Int -> 1}<!>();
<!INAPPLICABLE_CANDIDATE!>(fun Int.() = 1)<!>()
"sd".<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>()
"sd".(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)()
val i : Int? = null
i.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>();
i.(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)();
<!INAPPLICABLE_CANDIDATE!>{}<!><Int>()
1?.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>()
1?.(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)()
1.<!UNRESOLVED_REFERENCE!>{}<!>()
}
@@ -14,5 +14,5 @@ operator fun A.set(i: IFoo, newValue: Int) {}
fun withVararg(vararg xs: Int) = 42
fun test1() {
<!UNRESOLVED_REFERENCE!>A[::withVararg] += 1<!>
}
A[::withVararg] <!UNRESOLVED_REFERENCE!>+=<!> 1
}
@@ -45,7 +45,7 @@ fun test() {
x4 checkType { _<Function1<Int, Unit>>() }
{ y: Int -> fun named14(): Int {return 1} }
val b = <!UNRESOLVED_REFERENCE!>(<!EXPRESSION_REQUIRED!>fun named15(): Boolean { return true }<!>)<!>()
val b = (<!EXPRESSION_REQUIRED, UNRESOLVED_REFERENCE!>fun named15(): Boolean { return true }<!>)()
baz(<!EXPRESSION_REQUIRED!>fun named16(){}<!>)
}
@@ -18,4 +18,4 @@ enum class TestMultipleConstructors(val x: String = "", val y: Int = 0) {
enum class TestVarargs(val x: Int) {
TEST;
constructor(vararg xs: Any) : this(xs.size)
}
}
@@ -35,7 +35,7 @@ fun test4() {
// should be an error on receiver, shouldn't be thrown away
fun test5() {
1.<!UNRESOLVED_REFERENCE!>(fun String.()=1)<!>()
1.(<!UNRESOLVED_REFERENCE!>fun String.()=1<!>)()
}
fun <R: Any> R?.sure() : R = this!!
@@ -1,9 +1,9 @@
// !WITH_NEW_INFERENCE
val receiver = { Int.(<!SYNTAX!><!>) <!SYNTAX!>-><!> }
val receiverWithParameter = { <!UNRESOLVED_REFERENCE!>Int.(a)<!> <!SYNTAX!>-><!> }
val receiverWithParameter = { Int.(<!UNRESOLVED_REFERENCE!>a<!>) <!SYNTAX!>-><!> }
val receiverAndReturnType = { Int.(<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
val receiverAndReturnTypeWithParameter = { Int.(a<!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
val receiverAndReturnTypeWithParameter = { Int.(<!UNRESOLVED_REFERENCE!>a<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
val returnType = { (<!SYNTAX!><!>): Int -> 5 }
val returnTypeWithParameter = { <!COMPONENT_FUNCTION_MISSING!>(b: Int): Int<!> -> 5 }
@@ -8,4 +8,3 @@ fun <F, G> getMap() : Map<F, G> = throw Exception()
fun bar123() {
foo(<!INAPPLICABLE_CANDIDATE!>getMap<!>(
<!SYNTAX!><!>}
@@ -2,4 +2,4 @@ package l
fun test(a: Int) {
if (a <!UNRESOLVED_REFERENCE!>in<!><!SYNTAX!><!> ) {} //a is not unresolved
}
}
@@ -2,4 +2,4 @@ package l
fun test(a: Int) {
if (a in<!SYNTAX!><!> ) {} //a is not unresolved
}
}
@@ -8,4 +8,4 @@ class Test {
open class StaticClass
open inner class InnerClass
}
}
+1 -1
View File
@@ -14,4 +14,4 @@ class Outer {
inner class Inner2 : FinalNested()
inner class Inner3 : OpenInner()
inner class Inner4 : FinalInner()
}
}
+2 -2
View File
@@ -3,5 +3,5 @@ fun Any.foo1() : (i : Int) -> Unit {
}
fun test(a : Any) {
a.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
}
<!INAPPLICABLE_CANDIDATE!>a.foo1()<!>()
}
@@ -30,7 +30,7 @@ fun test() {
oldAndNew %= 1
val onlyOld = OnlyOld()
<!INAPPLICABLE_CANDIDATE!>onlyOld %= 1<!>
onlyOld <!INAPPLICABLE_CANDIDATE!>%=<!> 1
val onlyNew = OnlyNew()
onlyNew %= 1
@@ -40,4 +40,4 @@ fun test() {
var modAndRemAssign = ModAndRemAssign()
modAndRemAssign %= 1
}
}
@@ -27,6 +27,6 @@ fun foo() {
r.remAssign(1)
val m = JustMod
<!UNRESOLVED_REFERENCE!>m %= 1<!>
m <!UNRESOLVED_REFERENCE!>%=<!> 1
m.modAssign(1)
}
}
@@ -25,7 +25,7 @@ fun test() {
<!INAPPLICABLE_CANDIDATE!>takeInt<!>(ModAndRem % 1)
val c = ModAssignAndRemAssign
<!INAPPLICABLE_CANDIDATE!>c %= ""<!>
c <!INAPPLICABLE_CANDIDATE!>%=<!> ""
var c1 = RemAndModAssign
c1 %= 1
@@ -36,4 +36,4 @@ fun test() {
c2 %= 1
}
fun takeInt(x: Int) {}
fun takeInt(x: Int) {}
@@ -20,7 +20,7 @@ object MismatchingTypes {
fun testMismatchingTypes() {
++<!INAPPLICABLE_CANDIDATE!>MismatchingTypes[0]<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingTypes[0]<!>++
<!UNRESOLVED_REFERENCE!>MismatchingTypes[0] += 1<!>
MismatchingTypes[0] <!UNRESOLVED_REFERENCE!>+=<!> 1
}
object MismatchingArities1 {
@@ -36,10 +36,9 @@ object MismatchingArities2 {
fun testMismatchingArities() {
++<!INAPPLICABLE_CANDIDATE!>MismatchingArities1[0]<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingArities1[0]<!>++
<!UNRESOLVED_REFERENCE!>MismatchingArities1[0] += 1<!>
MismatchingArities1[0] <!UNRESOLVED_REFERENCE!>+=<!> 1
++<!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!>++
<!UNRESOLVED_REFERENCE!><!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!> += 1<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!> <!UNRESOLVED_REFERENCE!>+=<!> 1
}
@@ -1,12 +1,12 @@
fun intBinEq() {
var x = 0
<!UNRESOLVED_REFERENCE!>x += 'a'<!>
x <!UNRESOLVED_REFERENCE!>+=<!> 'a'
x += 1.toByte()
x += 1.toShort()
x += 1L
x += 1f
x += 1.0
<!UNRESOLVED_REFERENCE!>x *= 'a'<!>
x <!UNRESOLVED_REFERENCE!>*=<!> 'a'
x *= 1.toByte()
x *= 1.toShort()
x *= 1L
@@ -16,14 +16,14 @@ fun intBinEq() {
fun shortBinEq() {
var x = 0.toShort()
<!UNRESOLVED_REFERENCE!>x += 'a'<!>
x <!UNRESOLVED_REFERENCE!>+=<!> 'a'
x += 1.toByte()
x += 1.toShort()
x += 1L
x += 1f
x += 1.0
<!UNRESOLVED_REFERENCE!>x *= 'a'<!>
x <!UNRESOLVED_REFERENCE!>*=<!> 'a'
x *= 1.toByte()
x *= 1.toShort()
x *= 1L
@@ -16,5 +16,5 @@ fun test() {
val c = C()
c[0] += ""
var c1 = C1()
<!AMBIGUITY!>c1[0] += ""<!>
}
c1[0] <!AMBIGUITY!>+=<!> ""
}
@@ -19,5 +19,5 @@ public class J {
// FILE: k.kt
var A by J.staticNN
var B by J<!UNSAFE_CALL, UNSAFE_CALL!>.<!>staticN
var C by J.staticJ
var B by J<!UNSAFE_CALL!>.<!>staticN
var C by J.staticJ
@@ -1,2 +1,2 @@
// !WITH_NEW_INFERENCE
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!><!UNRESOLVED_REFERENCE!><<!><!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>sdf<!>()()<out Any>::<!UNRESOLVED_REFERENCE!>unwrap<!>
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!><!UNRESOLVED_REFERENCE!><<!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!>sdf<!>()<!>()<!><out Any>::<!UNRESOLVED_REFERENCE!>unwrap<!>
@@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) {
fun test2(f: (Int) -> Int) {
1.<!UNRESOLVED_REFERENCE!>f<!>(2)
2.<!UNRESOLVED_REFERENCE!>(f)<!>(2)
}
2.(<!UNRESOLVED_REFERENCE!>f<!>)(2)
}
@@ -1,17 +1,17 @@
// !WITH_NEW_INFERENCE
fun test1() {
1. <!UNRESOLVED_REFERENCE!>(fun String.(i: Int) = i )<!>(1)
1.<!UNRESOLVED_REFERENCE!>(label@ fun String.(i: Int) = i )<!>(1)
1. (<!UNRESOLVED_REFERENCE!>fun String.(i: Int) = i<!> )(1)
1.(<!UNRESOLVED_REFERENCE!>label@ fun String.(i: Int) = i<!> )(1)
}
fun test2(f: String.(Int) -> Unit) {
11.<!INAPPLICABLE_CANDIDATE!>(f)<!>(1)
11.<!INAPPLICABLE_CANDIDATE!>(f)<!>()
11.(<!INAPPLICABLE_CANDIDATE!>f<!>)(1)
11.(<!INAPPLICABLE_CANDIDATE!>f<!>)()
}
fun test3() {
fun foo(): String.(Int) -> Unit = {}
1.<!UNRESOLVED_REFERENCE!>(foo())<!>(1)
1.(<!UNRESOLVED_REFERENCE!>foo()<!>)(1)
}
@@ -2,11 +2,11 @@ class A(val x: (String.() -> Unit)?)
fun test(a: A) {
if (a.x != null) {
"".<!UNRESOLVED_REFERENCE!>(a.x)<!>()
"".(<!UNRESOLVED_REFERENCE!>a.x<!>)()
a.x("") // todo
(a.x)("")
}
"".<!UNRESOLVED_REFERENCE!>(a.x)<!>()
"".(<!UNRESOLVED_REFERENCE!>a.x<!>)()
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>("")
<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>("")
@@ -8,7 +8,7 @@ class B
val A.foo: B.() -> Unit get() = {}
fun test(a: A, b: B) {
b.<!UNRESOLVED_REFERENCE!>(a.foo)<!>()
b.(<!UNRESOLVED_REFERENCE!>a.foo<!>)()
(a.foo)(b)
a.foo(b)
@@ -25,7 +25,7 @@ fun test(a: A, b: B) {
with(b) {
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
a.<!INAPPLICABLE_CANDIDATE!>(foo)<!>()
a.(<!INAPPLICABLE_CANDIDATE!>foo<!>)()
(a.foo)()
@@ -50,7 +50,7 @@ class A {
class B
fun test(a: A, b: B) {
b.<!UNRESOLVED_REFERENCE!>(a.foo)<!>()
b.(<!UNRESOLVED_REFERENCE!>a.foo<!>)()
(a.foo)(b)
a.foo(b)
@@ -59,7 +59,7 @@ fun test(a: A, b: B) {
b.(foo)()
<!UNRESOLVED_REFERENCE!>(b.<!UNRESOLVED_REFERENCE!>foo<!>)<!>()
(<!UNRESOLVED_REFERENCE!>b.<!UNRESOLVED_REFERENCE!>foo<!><!>)()
foo(b)
(foo)(b)
@@ -67,7 +67,7 @@ fun test(a: A, b: B) {
with(b) {
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
a.<!INAPPLICABLE_CANDIDATE!>(foo)<!>()
a.(<!INAPPLICABLE_CANDIDATE!>foo<!>)()
(a.foo)()
@@ -8,7 +8,7 @@ fun foo(): String {
var t: String? = "y"
if (t == null) t = "x"
var x: Int? = null
if (x == null) <!UNRESOLVED_REFERENCE!>x += null<!>
if (x == null) x <!UNRESOLVED_REFERENCE!>+=<!> null
return t + s
}
@@ -7,4 +7,4 @@ interface Foo2 : <!INTERFACE_WITH_SUPERCLASS!>bar<!>, Foo {
}
open class Foo1() : bar(), bar, Foo, <!UNRESOLVED_REFERENCE!>Foo<!>() {}
open class Foo12 : bar(), bar {}
open class Foo12 : bar(), bar {}