Add more diagnostics to address invalid module

Relates to ^KT-42274
This commit is contained in:
Vladimir Dolzhenko
2020-10-12 13:03:22 +00:00
parent fa7104213c
commit 0e7e24c498
4 changed files with 39 additions and 18 deletions
@@ -165,6 +165,9 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone
throw e throw e
} }
} }
if (fileResult == null) {
file.clearInBlockModifications()
}
return fileResult return fileResult
} }
@@ -228,6 +231,7 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone
return AnalysisResult.EMPTY return AnalysisResult.EMPTY
} }
moduleDescriptor.assertValid()
try { try {
return KotlinResolveDataProvider.analyze( return KotlinResolveDataProvider.analyze(
project, project,
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.caches.resolve package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
@@ -102,13 +103,8 @@ internal class ProjectResolutionFacade(
private val resolverForProjectDependencies = dependencies + listOf(globalContext.exceptionTracker) private val resolverForProjectDependencies = dependencies + listOf(globalContext.exceptionTracker)
private fun computeModuleResolverProvider(): ResolverForProject<IdeaModuleInfo> { private fun computeModuleResolverProvider(): ResolverForProject<IdeaModuleInfo> {
val delegateResolverForProject: ResolverForProject<IdeaModuleInfo> val delegateResolverForProject: ResolverForProject<IdeaModuleInfo> =
reuseDataFrom?.cachedResolverForProject ?: EmptyResolverForProject()
if (reuseDataFrom != null) {
delegateResolverForProject = reuseDataFrom.cachedResolverForProject
} else {
delegateResolverForProject = EmptyResolverForProject()
}
val allModuleInfos = (allModules ?: getModuleInfosFromIdeaModel(project, (settings as? PlatformAnalysisSettingsImpl)?.platform)) val allModuleInfos = (allModules ?: getModuleInfosFromIdeaModel(project, (settings as? PlatformAnalysisSettingsImpl)?.platform))
.toMutableSet() .toMutableSet()
@@ -154,13 +150,29 @@ internal class ProjectResolutionFacade(
internal fun getAnalysisResultsForElements(elements: Collection<KtElement>): AnalysisResult { internal fun getAnalysisResultsForElements(elements: Collection<KtElement>): AnalysisResult {
assert(elements.isNotEmpty()) { "elements collection should not be empty" } assert(elements.isNotEmpty()) { "elements collection should not be empty" }
val slruCache = analysisResultsSimpleLock.guarded { val cache = analysisResultsSimpleLock.guarded {
analysisResults.value!! analysisResults.value!!
} }
val results = elements.map { val results =
val perFileCache = slruCache[it.containingKtFile] elements.map {
perFileCache.getAnalysisResults(it) val containingKtFile = it.containingKtFile
} val perFileCache = cache[containingKtFile]
try {
perFileCache.getAnalysisResults(it)
} catch (e: Throwable) {
if (e is ControlFlowException) {
throw e
}
val actualCache = analysisResultsSimpleLock.guarded {
analysisResults.upToDateOrNull?.get()
}
if (cache !== actualCache) {
throw IllegalStateException("Cache has been invalidated during performing analysis for $containingKtFile", e)
}
throw e
}
}
val withError = results.firstOrNull { it.isError() } val withError = results.firstOrNull { it.isError() }
val bindingContext = CompositeBindingContext.create(results.map { it.bindingContext }) val bindingContext = CompositeBindingContext.create(results.map { it.bindingContext })
if (withError != null) { if (withError != null) {
@@ -8,10 +8,8 @@ package org.jetbrains.kotlin.idea.caches.trackers
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.SimpleModificationTracker import com.intellij.openapi.util.SimpleModificationTracker
import com.intellij.pom.tree.TreeAspect import com.intellij.pom.tree.TreeAspect
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.util.application.getServiceSafe import org.jetbrains.kotlin.idea.util.application.getServiceSafe
import org.jetbrains.kotlin.psi.KtFile
/** /**
* Tested in OutOfBlockModificationTestGenerated * Tested in OutOfBlockModificationTestGenerated
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.caches.trackers package org.jetbrains.kotlin.idea.caches.trackers
import com.intellij.lang.ASTNode import com.intellij.lang.ASTNode
import com.intellij.openapi.Disposable
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
@@ -27,6 +28,8 @@ import com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.PROPERTY_CHANGE
import com.intellij.psi.impl.PsiTreeChangePreprocessor import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analyzer.ModuleDescriptorListener
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.kdoc.psi.api.KDoc
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
@@ -39,7 +42,7 @@ val KOTLIN_CONSOLE_KEY = Key.create<Boolean>("kotlin.console")
* Tested in OutOfBlockModificationTestGenerated * Tested in OutOfBlockModificationTestGenerated
*/ */
// FIX ME WHEN BUNCH 193 REMOVED // FIX ME WHEN BUNCH 193 REMOVED
abstract class KotlinCodeBlockModificationListenerCompat(protected val project: Project) : PsiTreeChangePreprocessor { abstract class KotlinCodeBlockModificationListenerCompat(protected val project: Project) : PsiTreeChangePreprocessor, Disposable {
protected val modificationTrackerImpl: PsiModificationTrackerImpl = protected val modificationTrackerImpl: PsiModificationTrackerImpl =
PsiModificationTracker.SERVICE.getInstance(project) as PsiModificationTrackerImpl PsiModificationTracker.SERVICE.getInstance(project) as PsiModificationTrackerImpl
@@ -62,7 +65,7 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project:
kotlinOutOfCodeBlockTrackerImpl = kotlinOutOfCodeBlockTrackerProducer() kotlinOutOfCodeBlockTrackerImpl = kotlinOutOfCodeBlockTrackerProducer()
kotlinOutOfCodeBlockTracker = kotlinOutOfCodeBlockTrackerImpl kotlinOutOfCodeBlockTracker = kotlinOutOfCodeBlockTrackerImpl
val model = PomManager.getModel(project) val model = PomManager.getModel(project)
val messageBusConnection = project.messageBus.connect(project) val messageBusConnection = project.messageBus.connect(this)
model.addModelListener(object : PomModelListener { model.addModelListener(object : PomModelListener {
override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean { override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean {
return aspect == treeAspect return aspect == treeAspect
@@ -125,6 +128,10 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project:
} }
} }
override fun dispose() {
kotlinOutOfCodeBlockTrackerImpl.incModificationCount()
}
companion object { companion object {
private fun isReplLine(file: VirtualFile): Boolean { private fun isReplLine(file: VirtualFile): Boolean {
return file.getUserData(KOTLIN_CONSOLE_KEY) == true return file.getUserData(KOTLIN_CONSOLE_KEY) == true
@@ -176,7 +183,7 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project:
// dirty scope for whitespaces and comments is the element itself // dirty scope for whitespaces and comments is the element itself
if (element is PsiWhiteSpace || element is PsiComment || element is KDoc) return element if (element is PsiWhiteSpace || element is PsiComment || element is KDoc) return element
return getInsideCodeBlockModificationScope(element)?.blockDeclaration ?: null return getInsideCodeBlockModificationScope(element)?.blockDeclaration
} }
fun getInsideCodeBlockModificationScope(element: PsiElement): BlockModificationScopeElement? { fun getInsideCodeBlockModificationScope(element: PsiElement): BlockModificationScopeElement? {
@@ -267,7 +274,7 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project:
is KtSecondaryConstructor -> { is KtSecondaryConstructor -> {
blockDeclaration blockDeclaration
?.takeIf { .takeIf {
it.bodyExpression?.isAncestor(element) ?: false || it.getDelegationCallOrNull()?.isAncestor(element) ?: false it.bodyExpression?.isAncestor(element) ?: false || it.getDelegationCallOrNull()?.isAncestor(element) ?: false
}?.let { ktConstructor -> }?.let { ktConstructor ->
PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java)?.let { PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java)?.let {