FIR IDE: introduce FIR IDE specific out of block modification tracker

This commit is contained in:
Ilya Kirillov
2020-11-03 21:34:31 +03:00
parent 6c1faec171
commit 880e76b203
24 changed files with 484 additions and 15 deletions
@@ -86,6 +86,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.AbstractFirMultiModuleLazyRes
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.AbstractFileStructureTest
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
import org.jetbrains.kotlin.idea.frontend.api.scopes.AbstractMemberScopeByFqNameTest
import org.jetbrains.kotlin.idea.frontend.api.symbols.AbstractSymbolFromLibraryPointerRestoreTest
import org.jetbrains.kotlin.idea.frontend.api.symbols.AbstractSymbolsByFqNameBuildingTest
@@ -1037,6 +1038,9 @@ fun main(args: Array<String>) {
testClass<AbstractFirLazyDeclarationResolveTest> {
model("lazyResolve")
}
testClass<AbstractProjectWideOutOfBlockKotlinModificationTrackerTest> {
model("outOfBlockProjectWide")
}
testClass<AbstractFileStructureTest> {
model("fileStructure")
}
@@ -7,21 +7,13 @@ package org.jetbrains.kotlin.idea.fir.low.level.api
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver
import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSessionFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSessionProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSessionProviderStorage
import org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSourcesSession
import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirOutOfBlockModificationTrackerFactory
import org.jetbrains.kotlin.idea.util.cachedValue
import org.jetbrains.kotlin.idea.util.getValue
import java.util.concurrent.ConcurrentHashMap
@@ -29,7 +21,10 @@ import java.util.concurrent.ConcurrentHashMap
internal class FirIdeResolveStateService(project: Project) {
private val sessionProviderStorage = FirIdeSessionProviderStorage(project)
private val stateCache by cachedValue(project, KotlinCodeBlockModificationListener.getInstance(project).kotlinOutOfCodeBlockTracker) {
private val stateCache by cachedValue(
project,
project.service<KotlinFirOutOfBlockModificationTrackerFactory>().createProjectWideOutOfBlockModificationTracker(),
) {
ConcurrentHashMap<IdeaModuleInfo, FirModuleResolveStateImpl>()
}
@@ -68,7 +68,8 @@ private fun KtElement.getFirOfClosestParent(cache: Map<KtElement, FirElement>):
return null
}
fun KtElement.getNonLocalContainingOrThisDeclaration(): KtNamedDeclaration? {
internal inline fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDeclaration) -> Boolean = { true }): KtNamedDeclaration? {
var container: PsiElement? = this
while (container != null && container !is KtFile) {
if (container is KtNamedDeclaration
@@ -77,10 +78,19 @@ fun KtElement.getNonLocalContainingOrThisDeclaration(): KtNamedDeclaration? {
&& !KtPsiUtil.isLocal(container)
&& container !is KtEnumEntry
&& container.containingClassOrObject !is KtEnumEntry
&& predicate(container)
) {
return container
}
container = container.parent
}
return null
}
}
internal fun PsiElement.getNonLocalContainingInBodyDeclarationWith(): KtNamedDeclaration? =
getNonLocalContainingOrThisDeclaration { declaration ->
when (declaration) {
is KtNamedFunction -> declaration.bodyExpression?.isAncestor(this) == true
else -> false
}
}
@@ -5,12 +5,13 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.sessions
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.trackers.KotlinModuleOutOfCodeBlockModificationTracker
import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner
import org.jetbrains.kotlin.idea.fir.low.level.api.FirTransformerProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirOutOfBlockModificationTrackerFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE
import java.util.concurrent.ConcurrentHashMap
@@ -102,7 +103,9 @@ private class FromModuleViewSessionCache(
private class FirSessionWithModificationTracker(
val firSession: FirIdeSourcesSession,
) {
private val modificationTracker = KotlinModuleOutOfCodeBlockModificationTracker(firSession.moduleInfo.module)
private val modificationTracker = firSession.project.service<KotlinFirOutOfBlockModificationTrackerFactory>()
.createModuleOutOfBlockModificationTracker(firSession.moduleInfo.module)
private val timeStamp = modificationTracker.modificationCount
@Volatile
@@ -0,0 +1,91 @@
/*
* 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.trackers
import com.intellij.ProjectTopics
import com.intellij.lang.ASTNode
import com.intellij.openapi.Disposable
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModuleRootEvent
import com.intellij.openapi.roots.ModuleRootListener
import com.intellij.pom.PomManager
import com.intellij.pom.PomModelAspect
import com.intellij.pom.event.PomModelEvent
import com.intellij.pom.event.PomModelListener
import com.intellij.pom.tree.TreeAspect
import com.intellij.pom.tree.events.TreeChangeEvent
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingInBodyDeclarationWith
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileElementFactory
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import java.util.*
internal class KotlinFirModificationTrackerService(project: Project) : Disposable {
init {
val model = PomManager.getModel(project)
model.addModelListener(Listener())
val connection = project.messageBus.connect(this)
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
override fun rootsChanged(event: ModuleRootEvent) {
projectGlobalOutOfBlockInKotlinFilesModificationCount++
// todo increase modificationCountForModule
}
})
}
internal var projectGlobalOutOfBlockInKotlinFilesModificationCount = 0L
private set
internal fun getOutOfBlockModificationCountForModules(module: Module): Long =
modificationCountForModule[module] ?: 0L
private val modificationCountForModule = WeakHashMap<Module, Long>()
private val treeAspect = TreeAspect.getInstance(project)
override fun dispose() {}
private inner class Listener : PomModelListener {
override fun modelChanged(event: PomModelEvent) {
val changeSet = event.getChangeSet(treeAspect) as TreeChangeEvent? ?: return
if (changeSet.rootElement.psi.language != KotlinLanguage.INSTANCE) return
val changedElements = changeSet.changedElements
var isOutOfBlockChangeInAnyModule = false
changedElements.forEach { element ->
val isOutOfBlock = element.isOutOfBlockChange(changeSet)
isOutOfBlockChangeInAnyModule = isOutOfBlockChangeInAnyModule || isOutOfBlock
if (isOutOfBlock) {
element.psi.module?.let { module ->
modificationCountForModule.compute(module) { _, value -> (value ?: 0) + 1 }
}
}
}
if (isOutOfBlockChangeInAnyModule) {
projectGlobalOutOfBlockInKotlinFilesModificationCount++
}
}
private fun ASTNode.isOutOfBlockChange(changeSet: TreeChangeEvent): Boolean {
val nodes = changeSet.getChangesByElement(this).affectedChildren
return nodes.any { node ->
val psi = node.psi ?: return@any true
val container = psi.getNonLocalContainingInBodyDeclarationWith() ?: return@any true
!FileElementFactory.isReanalyzableContainer(container)
}
}
override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean =
treeAspect == aspect
}
}
@@ -0,0 +1,34 @@
/*
* 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.trackers
import com.intellij.openapi.components.service
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
class KotlinFirOutOfBlockModificationTrackerFactory(private val project: Project) {
fun createProjectWideOutOfBlockModificationTracker(): ModificationTracker =
KotlinFirOutOfBlockModificationTracker(project)
fun createModuleOutOfBlockModificationTracker(module: Module): ModificationTracker =
KotlinFirOutOfBlockModuleModificationTracker(module)
}
private class KotlinFirOutOfBlockModificationTracker(project: Project) : ModificationTracker {
private val trackerService = project.service<KotlinFirModificationTrackerService>()
override fun getModificationCount(): Long =
trackerService.projectGlobalOutOfBlockInKotlinFilesModificationCount
}
private class KotlinFirOutOfBlockModuleModificationTracker(private val module: Module) : ModificationTracker {
private val trackerService = module.project.service<KotlinFirModificationTrackerService>()
override fun getModificationCount(): Long =
trackerService.getOutOfBlockModificationCountForModules(module)
}
@@ -0,0 +1,5 @@
fun x() {
fun a() = <caret>
}
// OUT_OF_BLOCK: false
@@ -0,0 +1,3 @@
fun foo(): Int = <caret>42
// OUT_OF_BLOCK: false
@@ -0,0 +1,3 @@
fun foo() = <caret>42
// OUT_OF_BLOCK: true
@@ -0,0 +1,6 @@
fun foo(): Int {
<caret>println("")
return 10
}
// OUT_OF_BLOCK: false
@@ -0,0 +1,5 @@
fun foo() {
<caret>println("")
}
// OUT_OF_BLOCK: false
@@ -0,0 +1,6 @@
@Ann<caret>
fun foo() {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,6 @@
@Ann(<caret>)
fun foo() {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,5 @@
<caret> fun foo() {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,5 @@
fun foo(<caret>) {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,5 @@
fun fo<caret>o() {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,5 @@
fun foo(x: In<caret>) {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,5 @@
fun foo(): In<caret> {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,5 @@
fun <X<caret>>foo() {
println("")
}
// OUT_OF_BLOCK: true
@@ -0,0 +1,85 @@
/*
* 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.openapi.util.io.FileUtil
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.util.parentOfType
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.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() {
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 elementAtCaret = ktFile.findElementAtCaret()
val (initialStructureElement, initialFileStructure, initialModuleResolveState) = getStructureElementForKtElement(elementAtCaret)
Assert.assertEquals(expectedFqName, initialStructureElement.psi.getKotlinFqName()?.asString())
myFixture.type("hello")
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,
newModuleResolveState !== initialModuleResolveState
)
Assert.assertEquals(
"FileStructure state should change only of out of block modification",
shouldStructureElementBeRecreated,
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 getStructureElementForKtElement(element: KtElement): Triple<FileStructureElement, FileStructure, FirModuleResolveState> {
val moduleResolveState = LowLevelFirApiFacade.getResolveStateFor(element) as FirModuleResolveStateImpl
val fileStructure =
moduleResolveState.fileStructureCache.getFileStructure(element.containingKtFile, moduleResolveState.rootModuleSession.cache)
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:"
}
}
@@ -0,0 +1,50 @@
/*
* 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");
}
}
@@ -0,0 +1,37 @@
/*
* 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.trackers
import com.intellij.openapi.components.service
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiDocumentManager
import junit.framework.Assert
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import java.io.File
abstract class AbstractProjectWideOutOfBlockKotlinModificationTrackerTest : KotlinLightCodeInsightFixtureTestCase() {
override fun isFirPlugin(): Boolean = true
fun doTest(path: String) {
val testDataFile = File(path)
val fileText = FileUtil.loadFile(testDataFile)
myFixture.configureByText(testDataFile.name, fileText)
val textToType = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// TYPE:") ?: 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 tracker = project.service<KotlinFirOutOfBlockModificationTrackerFactory>().createProjectWideOutOfBlockModificationTracker()
val initialModificationCount = tracker.modificationCount
myFixture.type(textToType)
PsiDocumentManager.getInstance(project).commitAllDocuments()
val afterTypingModificationCount = tracker.modificationCount
Assert.assertEquals(outOfBlock, initialModificationCount != afterTypingModificationCount)
}
companion object {
private const val DEFAULT_TEXT_TO_TYPE = "hello"
}
}
@@ -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.trackers;
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 ProjectWideOutOfBlockKotlinModificationTrackerTestGenerated extends AbstractProjectWideOutOfBlockKotlinModificationTrackerTest {
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");
}
}
+2 -1
View File
@@ -111,7 +111,8 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
implementationClass="org.jetbrains.kotlin.idea.codeInsight.KotlinHighLevelExpressionTypeProvider"/>
<highlightingPassFactory implementation="org.jetbrains.kotlin.idea.fir.highlighter.KotlinDiagnosticHighlightingPassFactory"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirModificationTrackerService"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirOutOfBlockModificationTrackerFactory"/>
</extensions>
<!-- scripts -->