FIR IDE: introduce ProjectWideOutOfBlockKotlinModificationTrackerTest
This commit is contained in:
@@ -84,6 +84,7 @@ import org.jetbrains.kotlin.idea.fir.AbstractKtDeclarationAndFirDeclarationEqual
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirLazyDeclarationResolveTest
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirMultiModuleLazyResolveTest
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.AbstractFileStructureTest
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.AbstractFileStructureAndOutOfBlockModificationTrackerConsistencyTest
|
||||
import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest
|
||||
import org.jetbrains.kotlin.idea.frontend.api.fir.AbstractResolveCallTest
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.AbstractProjectWideOutOfBlockKotlinModificationTrackerTest
|
||||
@@ -1041,6 +1042,9 @@ fun main(args: Array<String>) {
|
||||
testClass<AbstractProjectWideOutOfBlockKotlinModificationTrackerTest> {
|
||||
model("outOfBlockProjectWide")
|
||||
}
|
||||
testClass<AbstractFileStructureAndOutOfBlockModificationTrackerConsistencyTest> {
|
||||
model("outOfBlockProjectWide")
|
||||
}
|
||||
testClass<AbstractFileStructureTest> {
|
||||
model("fileStructure")
|
||||
}
|
||||
|
||||
+13
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.idea.fir.low.level.api.element.builder
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver
|
||||
@@ -13,9 +14,11 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.ThreadSafe
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureCache
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureElement
|
||||
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||
|
||||
/**
|
||||
@@ -53,6 +56,16 @@ internal class FirElementBuilder {
|
||||
return psi.getFirOfClosestParent(mappings)?.second
|
||||
?: error("FirElement is not found for:\n${element.getElementTextInContext()}")
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun getStructureElementFor(
|
||||
element: KtElement,
|
||||
moduleFileCache: ModuleFileCache,
|
||||
fileStructureCache: FileStructureCache,
|
||||
): FileStructureElement {
|
||||
val fileStructure = fileStructureCache.getFileStructure(element.containingKtFile, moduleFileCache)
|
||||
return fileStructure.getStructureElementFor(element)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtElement.getFirOfClosestParent(cache: Map<KtElement, FirElement>): Pair<KtElement, FirElement>? {
|
||||
|
||||
+16
-35
@@ -12,63 +12,49 @@ import junit.framework.Assert
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacade
|
||||
import org.jetbrains.kotlin.idea.search.getKotlinFqName
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.AbstractProjectWideOutOfBlockKotlinModificationTrackerTest
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.util.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractReanalyzableFileStructureElementCreationTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
abstract class AbstractFileStructureAndOutOfBlockModificationTrackerConsistencyTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override fun isFirPlugin(): Boolean = true
|
||||
|
||||
fun doTest(path: String) {
|
||||
val testDataFile = File(path)
|
||||
val initialFileText = FileUtil.loadFile(testDataFile)
|
||||
val ktFile = myFixture.configureByText(testDataFile.name, initialFileText) as KtFile
|
||||
val expectedFqName =
|
||||
InTextDirectivesUtils.findStringWithPrefixes(initialFileText, STRUCTURE_ELEMENT_FQ_NAME_DIRECTIVE)
|
||||
?: error("Please specify // STRUCTURE_ELEMENT directive")
|
||||
val shouldStructureElementBeRecreated =
|
||||
InTextDirectivesUtils.getPrefixedBoolean(initialFileText, SHOULD_ELEMENT_BE_RECREATED)
|
||||
?: error("Please specify // SHOULD_ELEMENT_BE_RECREATED directive")
|
||||
val fileText = FileUtil.loadFile(testDataFile)
|
||||
val ktFile = myFixture.configureByText(testDataFile.name, fileText) as KtFile
|
||||
val textToType = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// TYPE:")
|
||||
?: AbstractProjectWideOutOfBlockKotlinModificationTrackerTest.DEFAULT_TEXT_TO_TYPE
|
||||
val outOfBlock = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// OUT_OF_BLOCK:")
|
||||
?: error("Please, specify should out of block change happen or not by `// OUT_OF_BLOCK:` directive")
|
||||
|
||||
val elementAtCaret = ktFile.findElementAtCaret()
|
||||
val (initialStructureElement, initialFileStructure, initialModuleResolveState) = getStructureElementForKtElement(elementAtCaret)
|
||||
Assert.assertEquals(expectedFqName, initialStructureElement.psi.getKotlinFqName()?.asString())
|
||||
|
||||
myFixture.type("hello")
|
||||
myFixture.type(textToType)
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
|
||||
val newElementAtCaret = ktFile.findElementAtCaret()
|
||||
val (newStructureElement, newFileStructure, newModuleResolveState) = getStructureElementForKtElement(newElementAtCaret)
|
||||
Assert.assertEquals(
|
||||
"Structure elements should be build by the same KtDeclaration's",
|
||||
expectedFqName,
|
||||
newStructureElement.psi.getKotlinFqName()?.asString()
|
||||
)
|
||||
Assert.assertTrue("Structure elements should be different after typing", newStructureElement !== initialStructureElement)
|
||||
|
||||
Assert.assertEquals(
|
||||
"FirModuleResolveState should change only of out of block modification",
|
||||
shouldStructureElementBeRecreated,
|
||||
"FirModuleResolveState should change only on out of block modification",
|
||||
outOfBlock,
|
||||
newModuleResolveState !== initialModuleResolveState
|
||||
)
|
||||
Assert.assertEquals(
|
||||
"FileStructure state should change only of out of block modification",
|
||||
shouldStructureElementBeRecreated,
|
||||
"FileStructure state should change only on out of block modification",
|
||||
outOfBlock,
|
||||
initialFileStructure !== newFileStructure
|
||||
)
|
||||
}
|
||||
|
||||
private fun KtFile.findElementAtCaret(): KtElement {
|
||||
val elementAtCaret = findElementAt(myFixture.caretOffset)!!.parentOfType<KtElement>()!!
|
||||
if (elementAtCaret is KtDeclaration) {
|
||||
error("Expected element inside declaration but was\n${elementAtCaret.getElementTextInContext()}")
|
||||
}
|
||||
return elementAtCaret
|
||||
}
|
||||
private fun KtFile.findElementAtCaret(): KtElement =
|
||||
findElementAt(myFixture.caretOffset)!!.parentOfType()!!
|
||||
|
||||
private fun getStructureElementForKtElement(element: KtElement): Triple<FileStructureElement, FileStructure, FirModuleResolveState> {
|
||||
val moduleResolveState = LowLevelFirApiFacade.getResolveStateFor(element) as FirModuleResolveStateImpl
|
||||
@@ -77,9 +63,4 @@ abstract class AbstractReanalyzableFileStructureElementCreationTest : KotlinLigh
|
||||
val fileStructureElement = fileStructure.getStructureElementFor(element)
|
||||
return Triple(fileStructureElement, fileStructure, moduleResolveState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STRUCTURE_ELEMENT_FQ_NAME_DIRECTIVE = "// STRUCTURE_ELEMENT:"
|
||||
private const val SHOULD_ELEMENT_BE_RECREATED = "// SHOULD_ELEMENT_BE_RECREATED:"
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.file.structure;
|
||||
|
||||
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/outOfBlockProjectWide")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class FileStructureAndOutOfBlockModificationTrackerConsistencyTestGenerated extends AbstractFileStructureAndOutOfBlockModificationTrackerConsistencyTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInOutOfBlockProjectWide() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("localFun.kt")
|
||||
public void testLocalFun() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/localFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelExpressionBodyFunWithType.kt")
|
||||
public void testTopLevelExpressionBodyFunWithType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/topLevelExpressionBodyFunWithType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelExpressionBodyFunWithoutType.kt")
|
||||
public void testTopLevelExpressionBodyFunWithoutType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/topLevelExpressionBodyFunWithoutType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFunWithType.kt")
|
||||
public void testTopLevelFunWithType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/topLevelFunWithType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelUnitFun.kt")
|
||||
public void testTopLevelUnitFun() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/topLevelUnitFun.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionAnnotation.kt")
|
||||
public void testTypeInFunctionAnnotation() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionAnnotationParameter.kt")
|
||||
public void testTypeInFunctionAnnotationParameter() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionAnnotationParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionModifiers.kt")
|
||||
public void testTypeInFunctionModifiers() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionModifiers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionName.kt")
|
||||
public void testTypeInFunctionName() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionName.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionParams.kt")
|
||||
public void testTypeInFunctionParams() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionParamsType.kt")
|
||||
public void testTypeInFunctionParamsType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionParamsType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionReturnType.kt")
|
||||
public void testTypeInFunctionReturnType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionReturnType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeInFunctionTypeParams.kt")
|
||||
public void testTypeInFunctionTypeParams() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/outOfBlockProjectWide/typeInFunctionTypeParams.kt");
|
||||
}
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* 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.file.structure;
|
||||
|
||||
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/elementBuilder")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class ReanalyzableFileStructureElementCreationTestGenerated extends AbstractReanalyzableFileStructureElementCreationTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInElementBuilder() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/elementBuilder"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelExpressionBodyFunWithType.kt")
|
||||
public void testTopLevelExpressionBodyFunWithType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/elementBuilder/topLevelExpressionBodyFunWithType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelExpressionBodyFunWithoutType.kt")
|
||||
public void testTopLevelExpressionBodyFunWithoutType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/elementBuilder/topLevelExpressionBodyFunWithoutType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelFunWithType.kt")
|
||||
public void testTopLevelFunWithType() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/elementBuilder/topLevelFunWithType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelUnitFun.kt")
|
||||
public void testTopLevelUnitFun() throws Exception {
|
||||
runTest("idea/idea-frontend-fir/idea-fir-low-level-api/testdata/elementBuilder/topLevelUnitFun.kt");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -32,6 +32,6 @@ abstract class AbstractProjectWideOutOfBlockKotlinModificationTrackerTest : Kotl
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_TEXT_TO_TYPE = "hello"
|
||||
const val DEFAULT_TEXT_TO_TYPE = "hello"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user