Fix a problem where a sequence of out-of-block completions could lead to an inconsistent resolve session provided for a synthetic copy of a file
This commit is contained in:
+1
-1
@@ -103,7 +103,7 @@ public class KotlinCodeBlockModificationListener(modificationTracker: PsiModific
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isInsideCodeBlock(element: PsiElement?): Boolean {
|
||||
public fun isInsideCodeBlock(element: PsiElement?): Boolean {
|
||||
if (element is PsiFileSystemItem) return false
|
||||
if (element == null || element.getParent() == null) return true
|
||||
|
||||
|
||||
+7
-3
@@ -104,6 +104,10 @@ public class KotlinCacheService(val project: Project) {
|
||||
// we assume that all files come from the same module
|
||||
val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single()
|
||||
val syntheticFileModule = files.map { it.getModuleInfo() }.toSet().single()
|
||||
val dependenciesForSyntheticFileCache = listOf(
|
||||
PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT,
|
||||
KotlinOutOfBlockCompletionModificationTracker.getInstance(project)
|
||||
)
|
||||
return when {
|
||||
syntheticFileModule is ModuleSourceInfo -> {
|
||||
val dependentModules = syntheticFileModule.getDependentModules()
|
||||
@@ -114,7 +118,7 @@ public class KotlinCacheService(val project: Project) {
|
||||
syntheticFiles = files,
|
||||
reuseDataFromCache = getGlobalCache(targetPlatform),
|
||||
moduleFilter = { it in dependentModules },
|
||||
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -127,7 +131,7 @@ public class KotlinCacheService(val project: Project) {
|
||||
syntheticFiles = files,
|
||||
reuseDataFromCache = getGlobalLibrariesCache(targetPlatform),
|
||||
moduleFilter = { it == syntheticFileModule },
|
||||
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -143,7 +147,7 @@ public class KotlinCacheService(val project: Project) {
|
||||
targetPlatform,
|
||||
syntheticFiles = files,
|
||||
moduleFilter = { true },
|
||||
dependencies = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
|
||||
dependencies = dependenciesForSyntheticFileCache
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.caches.resolve
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.SimpleModificationTracker
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener
|
||||
|
||||
// NOTE: Sadly we must track out of block completion and drop sessions for synthetic files after the completion happens.
|
||||
// Synthetic file for completion can be modified without sending tree changed events and sequence of completions can lead to inconsistent
|
||||
// resolve session being cached for such a file otherwise.
|
||||
// This code is not tested. See KT-6216 for an example.
|
||||
public class KotlinOutOfBlockCompletionModificationTracker() : SimpleModificationTracker() {
|
||||
companion object {
|
||||
public fun getInstance(project: Project): KotlinOutOfBlockCompletionModificationTracker
|
||||
= ServiceManager.getService(project, javaClass<KotlinOutOfBlockCompletionModificationTracker>())!!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun performCompletionWithOutOfBlockTracking(completionPosition: PsiElement, body: () -> Unit) {
|
||||
if (KotlinCodeBlockModificationListener.isInsideCodeBlock(completionPosition)) {
|
||||
body()
|
||||
return
|
||||
}
|
||||
try {
|
||||
body()
|
||||
}
|
||||
finally {
|
||||
KotlinOutOfBlockCompletionModificationTracker.getInstance(completionPosition.getProject()).incModificationCount()
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -34,11 +34,11 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.performCompletionWithOutOfBlockTracking
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
@@ -197,6 +197,12 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
||||
val position = parameters.getPosition()
|
||||
if (position.getContainingFile() !is JetFile) return
|
||||
|
||||
performCompletionWithOutOfBlockTracking(position) {
|
||||
doComplete(parameters, position, result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doComplete(parameters: CompletionParameters, position: PsiElement, result: CompletionResultSet) {
|
||||
if (position.getNonStrictParentOfType<PsiComment>() != null) {
|
||||
// don't stop here, allow other contributors to run
|
||||
return
|
||||
|
||||
@@ -219,6 +219,9 @@
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.KotlinOutOfBlockCompletionModificationTracker"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.KotlinOutOfBlockCompletionModificationTracker"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade"
|
||||
serviceImplementation="org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user