FIR IDE: Add tests for resolving compiled declarations

Also, use correct index to find source for properties in
`FirIdeDeserializedDeclarationSourceProvider` - this bug
was revealed by the tests
This commit is contained in:
Roman Golyshev
2021-05-18 15:50:17 +03:00
committed by Space
parent 0fe068c6ce
commit 44f74888e0
23 changed files with 243 additions and 1 deletions
@@ -1072,6 +1072,9 @@ fun main(args: Array<String>) {
testClass<AbstractFirLazyDeclarationResolveTest> {
model("lazyResolve")
}
testClass<AbstractFirLibraryModuleDeclarationResolveTest> {
model("libraryModuleResolve", recursive = false)
}
testClass<AbstractProjectWideOutOfBlockKotlinModificationTrackerTest> {
model("outOfBlockProjectWide")
}
@@ -0,0 +1,18 @@
package library
fun topLevelFunction() {}
fun topLevelFunction(s: String) {}
val topLevelProperty: Int = 0
class TopLevelClass() {
constructor(s: String) : this() {}
fun memberFunction() {}
fun memberFunction(s: String) {}
val memberProperty: Int = 0
}
@@ -0,0 +1,7 @@
package test
import library.TopLevelClass
fun usage() {
TopLevelClass().<caret>memberFunction()
}
@@ -0,0 +1 @@
public final [BODY_RESOLVE] fun memberFunction(): R|kotlin/Unit|
@@ -0,0 +1,7 @@
package test
import library.TopLevelClass
fun usage() {
TopLevelClass().<caret>memberFunction("")
}
@@ -0,0 +1 @@
public final [BODY_RESOLVE] fun memberFunction([BODY_RESOLVE] s: R|kotlin/String|): R|kotlin/Unit|
@@ -0,0 +1,7 @@
package test
import library.TopLevelClass
fun usage() {
val a = TopLevelClass().<caret>memberProperty
}
@@ -0,0 +1,2 @@
public final [BODY_RESOLVE] val memberProperty: R|kotlin/Int|
[BODY_RESOLVE] public get(): R|kotlin/Int|
@@ -0,0 +1,7 @@
package test
import library.TopLevelClass
fun usage() {
val a: <caret>TopLevelClass
}
@@ -0,0 +1,13 @@
public final [BODY_RESOLVE] class TopLevelClass : R|kotlin/Any| {
public final [BODY_RESOLVE] fun memberFunction(): R|kotlin/Unit|
public final [BODY_RESOLVE] fun memberFunction([BODY_RESOLVE] s: R|kotlin/String|): R|kotlin/Unit|
public final [BODY_RESOLVE] val memberProperty: R|kotlin/Int|
[BODY_RESOLVE] public get(): R|kotlin/Int|
public [BODY_RESOLVE] constructor([BODY_RESOLVE] s: R|kotlin/String|): R|library/TopLevelClass|
public [BODY_RESOLVE] constructor(): R|library/TopLevelClass|
}
@@ -0,0 +1,7 @@
package test
import library.TopLevelClass
fun usage() {
val a = <caret>TopLevelClass()
}
@@ -0,0 +1 @@
public [BODY_RESOLVE] constructor(): R|library/TopLevelClass|
@@ -0,0 +1,7 @@
package test
import library.TopLevelClass
fun usage() {
val a = <caret>TopLevelClass("arg")
}
@@ -0,0 +1 @@
public [BODY_RESOLVE] constructor([BODY_RESOLVE] s: R|kotlin/String|): R|library/TopLevelClass|
@@ -0,0 +1,7 @@
package test
import library.topLevelFunction
fun usage() {
<caret>topLevelFunction()
}
@@ -0,0 +1 @@
public final [BODY_RESOLVE] fun topLevelFunction(): R|kotlin/Unit|
@@ -0,0 +1,7 @@
package test
import library.topLevelFunction
fun usage() {
<caret>topLevelFunction("")
}
@@ -0,0 +1 @@
public final [BODY_RESOLVE] fun topLevelFunction([BODY_RESOLVE] s: R|kotlin/String|): R|kotlin/Unit|
@@ -0,0 +1,7 @@
package test
import library.topLevelProperty
fun usage() {
val a = <caret>topLevelProperty
}
@@ -0,0 +1,2 @@
public final [BODY_RESOLVE] val topLevelProperty: R|kotlin/Int|
[BODY_RESOLVE] public get(): R|kotlin/Int|
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.fir.low.level.api
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.SdkAndMockLibraryProjectDescriptor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractFirLibraryModuleDeclarationResolveTest : KotlinLightCodeInsightFixtureTestCase() {
override fun isFirPlugin(): Boolean = true
override fun getProjectDescriptor(): LightProjectDescriptor {
val pathToLibraryFiles = File(testDataPath).resolve("_library")
assertExists(pathToLibraryFiles)
return SdkAndMockLibraryProjectDescriptor(pathToLibraryFiles.toString(), true)
}
/**
* We want to check that resolving 'compiled' PSI-elements (i.e. elements from libraries)
* works as expected.
*
* Compiled PSI-elements might come from indices, for example, and we need to be able to work with them
* and to resolve them to FIR declarations.
*/
fun doTest(path: String) {
val testDataFile = File(path)
val expectedFile = File(path.removeSuffix(".kt") + ".txt")
val ktFile = myFixture.configureByFile(testDataFile.name) as KtFile
val caretResolutionTarget = myFixture.elementAtCaret
require(caretResolutionTarget is KtDeclaration) {
"Element at caret should be referencing some declaration, but referenced ${caretResolutionTarget::class} instead"
}
// We intentionally use ktFile here as a context element, because resolving
// from compiled PSI-elements (e.g. caretResolutionTarget) is not yet supported
resolveWithClearCaches(ktFile) { resolveState ->
val renderedDeclaration = caretResolutionTarget.withFirDeclaration(resolveState) { firDeclaration ->
firDeclaration.render(FirRenderer.RenderMode.WithResolvePhases)
}
KotlinTestUtils.assertEqualsToFile(expectedFile, renderedDeclaration)
}
}
}
@@ -0,0 +1,76 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.fir.low.level.api;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class FirLibraryModuleDeclarationResolveTestGenerated extends AbstractFirLibraryModuleDeclarationResolveTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInLibraryModuleResolve() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve"), Pattern.compile("^(.+)\\.kt$"), null, false);
}
@TestMetadata("memberFunctionNoArgs.kt")
public void testMemberFunctionNoArgs() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/memberFunctionNoArgs.kt");
}
@TestMetadata("memberFunctionWithArgs.kt")
public void testMemberFunctionWithArgs() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/memberFunctionWithArgs.kt");
}
@TestMetadata("memberProperty.kt")
public void testMemberProperty() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/memberProperty.kt");
}
@TestMetadata("topLevelClass.kt")
public void testTopLevelClass() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/topLevelClass.kt");
}
@TestMetadata("topLevelClassPrimaryConstructor.kt")
public void testTopLevelClassPrimaryConstructor() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/topLevelClassPrimaryConstructor.kt");
}
@TestMetadata("topLevelClassSecondaryConstructor.kt")
public void testTopLevelClassSecondaryConstructor() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/topLevelClassSecondaryConstructor.kt");
}
@TestMetadata("topLevelFunctionNoArgs.kt")
public void testTopLevelFunctionNoArgs() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/topLevelFunctionNoArgs.kt");
}
@TestMetadata("topLevelFunctionWithArgs.kt")
public void testTopLevelFunctionWithArgs() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/topLevelFunctionWithArgs.kt");
}
@TestMetadata("topLevelProperty.kt")
public void testTopLevelProperty() throws Exception {
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/libraryModuleResolve/topLevelProperty.kt");
}
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSession
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyFqnNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelTypeAliasFqNameIndex
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -55,7 +56,7 @@ object FirIdeDeserializedDeclarationSourceProvider {
private fun provideSourceForProperty(property: FirProperty, project: Project): PsiElement? {
val candidates = if (property.isTopLevel) {
KotlinTopLevelFunctionFqnNameIndex.getInstance().get(
KotlinTopLevelPropertyFqnNameIndex.getInstance().get(
property.symbol.callableId.asSingleFqName().asString(),
project,
property.scope(project)