FIR IDE: handle reference to package and outer classes

For a qualified name like `foo.bar.Outer.Inner`, FIR represents it as
one atomic FIR element. Hence, to properly resolve these names to the
corresponding package and class, we need some additional work.

Original commit: 84f8d4d315f30cec46b4f50bbeafe834215dd057

GitOrigin-RevId: ef33f5fd039acfae0e4f171bc9f7a831131fde83
This commit is contained in:
Tianyu Geng
2022-01-22 11:05:13 +00:00
committed by intellij-monorepo-bot
parent 097eca7d97
commit dcd76e7309
20 changed files with 205 additions and 16 deletions
@@ -2,13 +2,11 @@
package org.jetbrains.kotlin.idea.fir.resolve
import org.jetbrains.kotlin.idea.completion.test.configureWithExtraFile
import org.jetbrains.kotlin.idea.fir.invalidateCaches
import org.jetbrains.kotlin.idea.resolve.AbstractReferenceResolveTest
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.utils.IgnoreTests
abstract class AbstractFirReferenceResolveTest : AbstractReferenceResolveTest() {
override fun isFirPlugin(): Boolean = true
@@ -20,13 +18,4 @@ abstract class AbstractFirReferenceResolveTest : AbstractReferenceResolveTest()
project.invalidateCaches(myFixture.file as? KtFile)
super.tearDown()
}
override fun doTest(path: String) {
assert(path.endsWith(".kt")) { path }
myFixture.configureWithExtraFile(path, ".Data")
IgnoreTests.runTestIfNotDisabledByFileDirective(testDataFile().toPath(), IgnoreTests.DIRECTIVES.IGNORE_FIR) {
performChecks()
}
}
}
@@ -886,4 +886,52 @@ public class FirReferenceResolveTestGenerated extends AbstractFirReferenceResolv
runTest("../idea/tests/testData/resolve/references/packageReference/kotlinPackageSecondQualifier.kt");
}
}
@TestMetadata("idea/testData/resolve/references/qualifiedAccess")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class QualifiedAccess extends AbstractFirReferenceResolveTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInQualifiedAccess() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/resolve/references/qualifiedAccess"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("callableReference1.kt")
public void testCallableReference1() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/callableReference1.kt");
}
@TestMetadata("callableReference2.kt")
public void testCallableReference2() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/callableReference2.kt");
}
@TestMetadata("callableReference3.kt")
public void testCallableReference3() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/callableReference3.kt");
}
@TestMetadata("ResolveFirstPackageOfFullyQualifiedReference.kt")
public void testResolveFirstPackageOfFullyQualifiedReference() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolveFirstPackageOfFullyQualifiedReference.kt");
}
@TestMetadata("ResolveFullyQualifiedCompanionObject.kt")
public void testResolveFullyQualifiedCompanionObject() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolveFullyQualifiedCompanionObject.kt");
}
@TestMetadata("ResolveOuterClassOfFullyQualifiedReference.kt")
public void testResolveOuterClassOfFullyQualifiedReference() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolveOuterClassOfFullyQualifiedReference.kt");
}
@TestMetadata("ResolvePackageOfFullyQualifiedReference.kt")
public void testResolvePackageOfFullyQualifiedReference() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolvePackageOfFullyQualifiedReference.kt");
}
}
}
@@ -215,6 +215,7 @@ object IgnoreTests {
const val FIR_IDENTICAL = "// FIR_IDENTICAL"
const val IGNORE_FE10_BINDING_BY_FIR = "// IGNORE_FE10_BINDING_BY_FIR"
const val IGNORE_FE10 = "// IGNORE_FE10"
}
enum class DirectivePosition {
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescrip
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.util.renderAsGotoImplementation
import org.jetbrains.kotlin.test.utils.IgnoreTests
import org.junit.Assert
import kotlin.test.assertTrue
@@ -29,7 +30,14 @@ abstract class AbstractReferenceResolveTest : KotlinLightCodeInsightFixtureTestC
protected open fun doTest(path: String) {
assert(path.endsWith(".kt")) { path }
myFixture.configureWithExtraFile(path, ".Data")
performChecks()
val controlDirective = if (isFirPlugin()) {
IgnoreTests.DIRECTIVES.IGNORE_FIR
} else {
IgnoreTests.DIRECTIVES.IGNORE_FE10
}
IgnoreTests.runTestIfNotDisabledByFileDirective(testDataFile().toPath(), controlDirective) {
performChecks()
}
}
protected fun performChecks() {
@@ -898,4 +898,52 @@ public abstract class ReferenceResolveTestGenerated extends AbstractReferenceRes
runTest("testData/resolve/references/packageReference/kotlinPackageSecondQualifier.kt");
}
}
@TestMetadata("idea/testData/resolve/references/qualifiedAccess")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class QualifiedAccess extends AbstractReferenceResolveTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInQualifiedAccess() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/resolve/references/qualifiedAccess"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("callableReference1.kt")
public void testCallableReference1() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/callableReference1.kt");
}
@TestMetadata("callableReference2.kt")
public void testCallableReference2() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/callableReference2.kt");
}
@TestMetadata("callableReference3.kt")
public void testCallableReference3() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/callableReference3.kt");
}
@TestMetadata("ResolveFirstPackageOfFullyQualifiedReference.kt")
public void testResolveFirstPackageOfFullyQualifiedReference() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolveFirstPackageOfFullyQualifiedReference.kt");
}
@TestMetadata("ResolveFullyQualifiedCompanionObject.kt")
public void testResolveFullyQualifiedCompanionObject() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolveFullyQualifiedCompanionObject.kt");
}
@TestMetadata("ResolveOuterClassOfFullyQualifiedReference.kt")
public void testResolveOuterClassOfFullyQualifiedReference() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolveOuterClassOfFullyQualifiedReference.kt");
}
@TestMetadata("ResolvePackageOfFullyQualifiedReference.kt")
public void testResolvePackageOfFullyQualifiedReference() throws Exception {
runTest("idea/testData/resolve/references/qualifiedAccess/ResolvePackageOfFullyQualifiedReference.kt");
}
}
}
@@ -1,3 +1,4 @@
// FIR_COMPARISON
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtObjectDeclaration
// OPTIONS: usages
class Foo {
@@ -1,3 +1,4 @@
// FIR_COMPARISON
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtObjectDeclaration
// OPTIONS: usages
class Foo {
@@ -1,3 +1,4 @@
// FIR_COMPARISON
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtProperty
// OPTIONS: usages
fun foo(): Any {
@@ -1 +1 @@
Value read 6 return Bar
Value read 7 return Bar
@@ -1,3 +1,4 @@
// FIR_COMPARISON
// PSI_ELEMENT: org.jetbrains.kotlin.psi.KtProperty
// OPTIONS: usages
fun foo(): Any {
@@ -1 +1 @@
Value read 7 return Bar
Value read 8 return Bar
@@ -1,5 +1,3 @@
// IGNORE_FIR
package test
class Conflict
@@ -1,3 +1,4 @@
// IGNORE_FIR
package test
object Conflict
@@ -0,0 +1,13 @@
package foo.bar.baz
class AA {
class BB {
companion object
}
}
fun test() {
val b = f<caret>oo.bar.baz.AA.BB
}
// REF: foo
@@ -0,0 +1,14 @@
// IGNORE_FIR
package foo.bar.baz
class AA {
class BB {
companion object
}
}
fun test() {
val b = foo.bar.baz.AA.B<caret>B
}
// REF: companion object of (in foo.bar.baz.AA).BB
@@ -0,0 +1,13 @@
package foo.bar.baz
class AA {
class BB {
companion object
}
}
fun test() {
val b = foo.bar.baz.A<caret>A.BB
}
// REF: (foo.bar.baz).AA
@@ -0,0 +1,13 @@
package foo.bar.baz
class AA {
class BB {
companion object
}
}
fun test() {
val b = foo.bar.b<caret>az.AA.BB
}
// REF: baz
@@ -0,0 +1,11 @@
package foo.bar.baz
class AA {
fun foo() {}
}
fun test() {
A<caret>A::foo
}
// REF: (foo.bar.baz).AA
@@ -0,0 +1,14 @@
// IGNORE_FE10
package foo.bar.baz
class AA {
companion object {
fun foo() {}
}
}
fun test() {
A<caret>A::foo // FE1.0 won't resolve this
}
// REF: companion object of (foo.bar.baz).AA
@@ -0,0 +1,14 @@
// IGNORE_FE10
package foo.bar.baz
class AA {
companion object
}
fun AA.Companion.foo() {}
fun test() {
A<caret>A::foo // FE1.0 won't resolve this
}
// REF: companion object of (foo.bar.baz).AA