FIR IDE: introduce multi module lazy resolve tests
This commit is contained in:
@@ -88,6 +88,7 @@ import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest
|
|||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirLazyResolveTest
|
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirLazyResolveTest
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirMultiModuleResolveTest
|
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirMultiModuleResolveTest
|
||||||
import org.jetbrains.kotlin.idea.fir.AbstractKtDeclarationAndFirDeclarationEqualityChecker
|
import org.jetbrains.kotlin.idea.fir.AbstractKtDeclarationAndFirDeclarationEqualityChecker
|
||||||
|
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirMultiModuleLazyResolveTest
|
||||||
import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest
|
import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.AbstractResolveCallTest
|
import org.jetbrains.kotlin.idea.frontend.api.fir.AbstractResolveCallTest
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.scopes.AbstractMemberScopeByFqNameTest
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.AbstractMemberScopeByFqNameTest
|
||||||
@@ -1015,6 +1016,12 @@ fun main(args: Array<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testGroup("idea/idea-frontend-fir/idea-fir-low-level-api/tests", "idea/idea-frontend-fir/idea-fir-low-level-api/testdata") {
|
||||||
|
testClass<AbstractFirMultiModuleLazyResolveTest> {
|
||||||
|
model("multiModuleLazyResolve", recursive = false, extension = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
testGroup("idea/idea-fir/tests", "idea") {
|
testGroup("idea/idea-fir/tests", "idea") {
|
||||||
testClass<AbstractFirHighlightingTest> {
|
testClass<AbstractFirHighlightingTest> {
|
||||||
model("testData/highlighter")
|
model("testData/highlighter")
|
||||||
|
|||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
interface A
|
||||||
|
|
||||||
|
interface X : A
|
||||||
|
interface Y : A
|
||||||
|
|
||||||
|
interface F : Y, X
|
||||||
|
interface G : Y, X
|
||||||
|
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
FILE: main.kt
|
||||||
|
public abstract interface A : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public abstract interface X : R|A| {
|
||||||
|
}
|
||||||
|
public abstract interface Y : R|A| {
|
||||||
|
}
|
||||||
|
public abstract interface F : R|Y|, R|X| {
|
||||||
|
}
|
||||||
|
public abstract interface G : R|Y|, R|X| {
|
||||||
|
}
|
||||||
|
public final fun R|Y|.test(): R|kotlin/String?| {
|
||||||
|
lval a: R|kotlin/Int| = when (this@R|/test|) {
|
||||||
|
($subj$ is R|F|) -> {
|
||||||
|
Int(1)
|
||||||
|
}
|
||||||
|
($subj$ is R|G|) -> {
|
||||||
|
Int(2)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
^test Null(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
^test Null(null)
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
fun Y.test(): String? {
|
||||||
|
val a = when (this) {
|
||||||
|
is F -> 1
|
||||||
|
is G -> 2
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"modules" : [
|
||||||
|
{ "name": "main", "dependsOn": ["dependency"] },
|
||||||
|
{ "name": "dependency" }
|
||||||
|
],
|
||||||
|
"fileToResolve": { "module": "main", "file": "main.kt" },
|
||||||
|
"fails": true
|
||||||
|
}
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
|
||||||
|
import org.jetbrains.kotlin.idea.util.sourceRoots
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
abstract class AbstractFirMultiModuleLazyResolveTest : AbstractMultiModuleTest() {
|
||||||
|
override fun getTestDataPath(): String =
|
||||||
|
"${KotlinTestUtils.getHomeDirectory()}/idea/idea-frontend-fir/idea-fir-low-level-api/testdata/multiModuleLazyResolve/"
|
||||||
|
|
||||||
|
fun doTest(path: String) {
|
||||||
|
val testStructure = TestProjectStructureReader.read(Paths.get(path))
|
||||||
|
val modulesByNames = testStructure.modules.associate { moduleData ->
|
||||||
|
moduleData.name to module(moduleData.name)
|
||||||
|
}
|
||||||
|
testStructure.modules.forEach { moduleData ->
|
||||||
|
val module = modulesByNames.getValue(moduleData.name)
|
||||||
|
moduleData.dependsOnModules.forEach { dependencyName ->
|
||||||
|
module.addDependency(modulesByNames.getValue(dependencyName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val moduleToResolve = modulesByNames.getValue(testStructure.fileToResolve.moduleName)
|
||||||
|
val fileToAnalysePath = moduleToResolve.sourceRoots.first().url + "/" + testStructure.fileToResolve.relativeFilePath
|
||||||
|
|
||||||
|
val virtualFileToAnalyse = VirtualFileManager.getInstance().findFileByUrl(fileToAnalysePath)
|
||||||
|
?: error("File ${testStructure.fileToResolve.filePath} not found")
|
||||||
|
val ktFileToAnalyse = PsiManager.getInstance(project).findFile(virtualFileToAnalyse) as KtFile
|
||||||
|
val resolveState = LowLevelFirApiFacade.getResolveStateFor(ktFileToAnalyse)
|
||||||
|
|
||||||
|
val fails = testStructure.fails
|
||||||
|
|
||||||
|
try {
|
||||||
|
val fir = LowLevelFirApiFacade.getOrBuildFirFor(ktFileToAnalyse, resolveState, FirResolvePhase.BODY_RESOLVE)
|
||||||
|
KotlinTestUtils.assertEqualsToFile(File("$path/expected.txt"), fir.render())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (!fails) throw e
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (fails) {
|
||||||
|
throw AssertionError("Looks like test is passing, please remove // FAILS form the file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.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/multiModuleLazyResolve")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public class FirMultiModuleLazyResolveTestGenerated extends AbstractFirMultiModuleLazyResolveTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInMultiModuleLazyResolve() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/multiModuleLazyResolve"), Pattern.compile("^([^\\.]+)$"), null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whenWithHeiarchy")
|
||||||
|
public void testWhenWithHeiarchy() throws Exception {
|
||||||
|
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/multiModuleLazyResolve/whenWithHeiarchy/");
|
||||||
|
}
|
||||||
|
}
|
||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParser
|
||||||
|
import com.google.gson.JsonPrimitive
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
sealed class TestProjectStructure {
|
||||||
|
abstract val modules: List<TestProjectModule>
|
||||||
|
abstract val fileToResolve: FileToResolve
|
||||||
|
abstract val fails: Boolean
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parse(json: JsonElement): TestProjectStructure {
|
||||||
|
require(json is JsonObject)
|
||||||
|
val fails = if (json.has(FAILS_FIELD)) json.get(FAILS_FIELD).asBoolean else false
|
||||||
|
|
||||||
|
return MultiModuleTestProjectStructure(
|
||||||
|
json.getAsJsonArray("modules").map { TestProjectModule.parse(it) },
|
||||||
|
FileToResolve.parse(json.getAsJsonObject("fileToResolve")),
|
||||||
|
fails
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val FAILS_FIELD = "fails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class FileToResolve(val moduleName: String, val relativeFilePath: String) {
|
||||||
|
val filePath get() = "$moduleName/$relativeFilePath"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parse(json: JsonElement): FileToResolve {
|
||||||
|
require(json is JsonObject)
|
||||||
|
return FileToResolve(
|
||||||
|
moduleName = json.getString("module"),
|
||||||
|
relativeFilePath = json.getString("file")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MultiModuleTestProjectStructure(
|
||||||
|
override val modules: List<TestProjectModule>,
|
||||||
|
override val fileToResolve: FileToResolve,
|
||||||
|
override val fails: Boolean
|
||||||
|
) : TestProjectStructure()
|
||||||
|
|
||||||
|
data class TestProjectModule(val name: String, val dependsOnModules: List<String>) {
|
||||||
|
companion object {
|
||||||
|
fun parse(json: JsonElement): TestProjectModule {
|
||||||
|
require(json is JsonObject)
|
||||||
|
val dependencies = if (json.has(DEPENDS_ON_FIELD)) {
|
||||||
|
json.getAsJsonArray(DEPENDS_ON_FIELD).map { (it as JsonPrimitive).asString }
|
||||||
|
} else emptyList()
|
||||||
|
return TestProjectModule(
|
||||||
|
json.getString("name"),
|
||||||
|
dependencies
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val DEPENDS_ON_FIELD = "dependsOn"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TestProjectStructureReader {
|
||||||
|
fun read(testDirectory: Path, jsonFileName: String = "structure.json"): TestProjectStructure {
|
||||||
|
val jsonFile = testDirectory.resolve(jsonFileName)
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION") // AS 4.0
|
||||||
|
val json = JsonParser().parse(FileUtil.loadFile(jsonFile.toFile(), /*convertLineSeparators=*/true))
|
||||||
|
return TestProjectStructure.parse(json)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user