Force perform FULL analysis to avoid redundant analysis for the current open file
#KT-38687 Fixed
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.project
|
||||
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import com.intellij.psi.util.CachedValue
|
||||
@@ -12,6 +13,7 @@ import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.SLRUCache
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.cfg.ControlFlowInformationProvider
|
||||
import org.jetbrains.kotlin.container.get
|
||||
import org.jetbrains.kotlin.context.SimpleGlobalContext
|
||||
@@ -25,6 +27,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.util.analyzeControlFlow
|
||||
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener
|
||||
import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerCompat
|
||||
import org.jetbrains.kotlin.idea.caches.trackers.inBlockModificationCount
|
||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -151,6 +154,22 @@ class ResolveElementCache(
|
||||
assert(bodyResolveMode == BodyResolveMode.FULL)
|
||||
}
|
||||
|
||||
// KT-38687: There are lots of editor specific items like inlays, line markers, injected items etc
|
||||
// those require analysis: it is called with BodyResolveMode.PARTIAL or BodyResolveMode.PARTIAL_WITH_CFA almost simultaneously.
|
||||
// In the same time Kotlin Annotator (e.g. KotlinPsiChecker) requires BodyResolveMode.FULL analysis.
|
||||
//
|
||||
// While results of FULL could be reused by any of PARTIAL or PARTIAL_WITH_CFA analysis,
|
||||
// neither result of PARTIAL nor result of PARTIAL_WITH_CFA analyses could be reused by FULL analysis.
|
||||
//
|
||||
// Force perform FULL analysis to avoid redundant analysis for the current selected files.
|
||||
if (bodyResolveMode != BodyResolveMode.FULL && (!isUnitTestMode() || forceFullAnalysisModeInTests)) {
|
||||
val virtualFile = resolveElement.containingFile.virtualFile
|
||||
// applicable for real (physical) files only
|
||||
if (virtualFile != null && FileEditorManager.getInstance(resolveElement.project).selectedFiles.any { it == virtualFile }) {
|
||||
return getElementsAdditionalResolve(resolveElement, contextElements, BodyResolveMode.FULL)
|
||||
}
|
||||
}
|
||||
|
||||
// check if full additional resolve already performed and is up-to-date
|
||||
val fullResolveMap = fullResolveCache.value
|
||||
val cachedFullResolve = fullResolveMap[resolveElement]
|
||||
@@ -807,5 +826,10 @@ class ResolveElementCache(
|
||||
|
||||
override fun getTopDownAnalysisMode() = topDownAnalysisMode
|
||||
}
|
||||
|
||||
companion object {
|
||||
@set:TestOnly
|
||||
var forceFullAnalysisModeInTests: Boolean = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -26,11 +26,11 @@ import com.intellij.util.io.exists
|
||||
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
|
||||
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
|
||||
import org.jetbrains.kotlin.idea.perf.util.logMessage
|
||||
import org.jetbrains.kotlin.idea.project.ResolveElementCache
|
||||
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
|
||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
data class OpenProject(val projectPath: String, val projectName: String, val jdk: Sdk, val projectOpenAction: ProjectOpenAction)
|
||||
@@ -64,7 +64,7 @@ enum class ProjectOpenAction {
|
||||
val projectManagerEx = ProjectManagerEx.getInstanceEx()
|
||||
|
||||
val project = loadProjectWithName(projectPath, projectName)
|
||||
assertNotNull(project, "project $projectName at $projectPath is not loaded")
|
||||
?: error("project $projectName at $projectPath is not loaded")
|
||||
|
||||
runWriteAction {
|
||||
ProjectRootManager.getInstance(project).projectSdk = jdk
|
||||
@@ -123,6 +123,7 @@ enum class ProjectOpenAction {
|
||||
|
||||
open fun postOpenProject(project: Project, openProject: OpenProject) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread {
|
||||
ResolveElementCache.forceFullAnalysisModeInTests = true
|
||||
DumbService.getInstance(project).waitForSmartMode()
|
||||
|
||||
for (module in getModulesWithKotlinFiles(project)) {
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea
|
||||
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.kotlin.idea.project.ResolveElementCache
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.runAll
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
@@ -43,6 +47,16 @@ class C(param1: String = "", param2: Int = 0) {
|
||||
val factory: KtPsiFactory
|
||||
)
|
||||
|
||||
override fun tearDown() {
|
||||
runAll(
|
||||
ThrowableRunnable { ResolveElementCache.forceFullAnalysisModeInTests = false },
|
||||
ThrowableRunnable { super.tearDown() },
|
||||
)
|
||||
}
|
||||
|
||||
protected fun configureWithKotlin(@Language("kotlin") text: String): KtFile =
|
||||
myFixture.configureByText("Test.kt", text.trimIndent()) as KtFile
|
||||
|
||||
protected fun doTest(handler: Data.() -> Unit) {
|
||||
val file = myFixture.configureByText("Test.kt", FILE_TEXT) as KtFile
|
||||
val data = extractData(file)
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea
|
||||
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import junit.framework.TestCase
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
|
||||
@@ -15,6 +14,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.project.ResolveElementCache
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -291,12 +291,12 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
|
||||
fun testIncompleteFileAnnotationList() {
|
||||
val file = myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
val file = configureWithKotlin(
|
||||
"""
|
||||
@file
|
||||
import some.hello
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val fileAnnotationList = file.fileAnnotationList!!
|
||||
fileAnnotationList.analyze(BodyResolveMode.PARTIAL)
|
||||
@@ -336,16 +336,12 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
assertEmpty(context.diagnostics.all())
|
||||
}
|
||||
|
||||
private fun configureWithKotlin(@Language("kotlin") text: String): KtFile {
|
||||
return myFixture.configureByText("Test.kt", text.trimIndent()) as KtFile
|
||||
}
|
||||
|
||||
fun testPrimaryConstructorParameterFullAnalysis() {
|
||||
myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
configureWithKotlin(
|
||||
"""
|
||||
class My(param: Int = <caret>0)
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val defaultValue = myFixture.elementByOffset.getParentOfType<KtExpression>(true)!!
|
||||
// Kept to preserve correct behaviour of analyzeFully() on class internal elements
|
||||
@@ -355,11 +351,11 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
|
||||
fun testPrimaryConstructorAnnotationFullAnalysis() {
|
||||
myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
configureWithKotlin(
|
||||
"""
|
||||
class My @Deprecated("<caret>xyz") protected constructor(param: Int)
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val annotationArguments = myFixture.elementByOffset.getParentOfType<KtValueArgumentList>(true)!!
|
||||
|
||||
@@ -368,14 +364,14 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
|
||||
fun testFunctionParameterAnnotation() {
|
||||
val file = myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
val file = configureWithKotlin(
|
||||
"""
|
||||
annotation class Ann
|
||||
fun foo(@<caret>Ann p: Int) {
|
||||
bar()
|
||||
}
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val function = (file.declarations[1]) as KtFunction
|
||||
val typeRef = myFixture.elementByOffset.getParentOfType<KtTypeReference>(true)!!
|
||||
@@ -391,12 +387,12 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
|
||||
fun testPrimaryConstructorParameterAnnotation() {
|
||||
myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
configureWithKotlin(
|
||||
"""
|
||||
annotation class Ann
|
||||
class X(@set:<caret>Ann var p: Int)
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val typeRef = myFixture.elementByOffset.getParentOfType<KtTypeReference>(true)!!
|
||||
|
||||
@@ -408,8 +404,8 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
|
||||
fun testSecondaryConstructorParameterAnnotation() {
|
||||
val file = myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
val file = configureWithKotlin(
|
||||
"""
|
||||
annotation class Ann
|
||||
class X {
|
||||
constructor(@<caret>Ann p: Int) {
|
||||
@@ -417,7 +413,7 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
}
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val constructor = ((file.declarations[1]) as KtClass).secondaryConstructors[0]
|
||||
val typeRef = myFixture.elementByOffset.getParentOfType<KtTypeReference>(true)!!
|
||||
@@ -475,16 +471,28 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
}
|
||||
}
|
||||
|
||||
fun testPartialResolveIsAFullResolveForOpenedFile() {
|
||||
ResolveElementCache.forceFullAnalysisModeInTests = true
|
||||
doTest {
|
||||
val function = members[0] as KtFunction
|
||||
val bindingContextPartial = function.analyze(BodyResolveMode.PARTIAL)
|
||||
val bindingContextFull = function.analyze(BodyResolveMode.FULL)
|
||||
assert(bindingContextPartial === bindingContextFull) {
|
||||
"Partial resolve is forced to FULL resolve for a file currently opened in editor"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testKT14376() {
|
||||
val file = myFixture.configureByText("Test.kt", "object Obj(val x: Int)") as KtFile
|
||||
val file = configureWithKotlin("object Obj(val x: Int)")
|
||||
val nameRef = file.findDescendantOfType<KtNameReferenceExpression>()!!
|
||||
val bindingContext = nameRef.analyze(BodyResolveMode.PARTIAL)
|
||||
assert(bindingContext[BindingContext.REFERENCE_TARGET, nameRef]?.fqNameSafe?.asString() == "kotlin.Int")
|
||||
}
|
||||
|
||||
fun testResolveDefaultValueInPrimaryConstructor() {
|
||||
myFixture.configureByText(
|
||||
"Test.kt", """
|
||||
configureWithKotlin(
|
||||
"""
|
||||
class ClassA<N> (
|
||||
messenger: ClassB<N> = object : ClassB<N> {
|
||||
override fun methodOne<caret>(param: List<N>) {
|
||||
@@ -496,7 +504,7 @@ class ResolveElementCacheTest : AbstractResolveElementCacheTest() {
|
||||
fun methodOne(param: List<N>)
|
||||
}
|
||||
"""
|
||||
) as KtFile
|
||||
)
|
||||
|
||||
val methodOne = myFixture.elementByOffset.getParentOfType<KtFunction>(true)!!
|
||||
|
||||
|
||||
Reference in New Issue
Block a user