ResolutionFacade for synthetic files should be invalidated on changes in these synthetic files
Fixed EA-77017
This commit is contained in:
+38
-76
@@ -16,15 +16,16 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.asJava
|
package org.jetbrains.kotlin.asJava
|
||||||
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.openapi.util.Key
|
||||||
|
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 com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFileSystemItem
|
|
||||||
import com.intellij.psi.PsiInvalidElementAccessException
|
|
||||||
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
||||||
import com.intellij.psi.impl.PsiTreeChangeEventImpl
|
|
||||||
import com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.*
|
|
||||||
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
@@ -33,84 +34,40 @@ import org.jetbrains.kotlin.psi.psiUtil.parents
|
|||||||
/**
|
/**
|
||||||
* Tested in OutOfBlockModificationTestGenerated
|
* Tested in OutOfBlockModificationTestGenerated
|
||||||
*/
|
*/
|
||||||
class KotlinCodeBlockModificationListener(modificationTracker: PsiModificationTracker) : PsiTreeChangePreprocessor {
|
class KotlinCodeBlockModificationListener(
|
||||||
private val myModificationTracker = modificationTracker as PsiModificationTrackerImpl
|
modificationTracker: PsiModificationTracker,
|
||||||
|
private val project: Project,
|
||||||
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
private val treeAspect: TreeAspect
|
||||||
if (event.file !is KtFile) return
|
) {
|
||||||
|
init {
|
||||||
when (event.code) {
|
val model = PomManager.getModel(project)
|
||||||
BEFORE_CHILDREN_CHANGE,
|
@Suppress("NAME_SHADOWING")
|
||||||
BEFORE_PROPERTY_CHANGE,
|
val modificationTracker = modificationTracker as PsiModificationTrackerImpl
|
||||||
BEFORE_CHILD_MOVEMENT,
|
model.addModelListener(object: PomModelListener {
|
||||||
BEFORE_CHILD_REPLACEMENT,
|
override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean {
|
||||||
BEFORE_CHILD_ADDITION,
|
return aspect == treeAspect
|
||||||
BEFORE_CHILD_REMOVAL -> {
|
|
||||||
// skip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CHILD_ADDED,
|
override fun modelChanged(event: PomModelEvent) {
|
||||||
CHILD_REMOVED,
|
val changeSet = event.getChangeSet(treeAspect) as TreeChangeEvent? ?: return
|
||||||
CHILD_REPLACED -> {
|
val file = changeSet.rootElement.psi.containingFile as? KtFile ?: return
|
||||||
processChange(event.parent, event.oldChild, event.child)
|
if (changeSet.changedElements.any { !isInsideCodeBlock(it.psi) }) {
|
||||||
}
|
if (file.isPhysical) {
|
||||||
|
modificationTracker.incCounter()
|
||||||
CHILDREN_CHANGED -> {
|
}
|
||||||
if (!event.isGenericChange) {
|
incOutOfBlockModificationCount(file)
|
||||||
processChange(event.parent, event.parent, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
CHILD_MOVED,
|
|
||||||
PROPERTY_CHANGED -> {
|
|
||||||
myModificationTracker.incCounter()
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> LOG.error("Unknown code:" + event.code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun processChange(parent: PsiElement?, child1: PsiElement?, child2: PsiElement?) {
|
|
||||||
try {
|
|
||||||
if (!isInsideCodeBlock(parent)) {
|
|
||||||
if (parent != null && parent.containingFile is KtFile) {
|
|
||||||
myModificationTracker.incCounter()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
myModificationTracker.incOutOfCodeBlockModificationCounter()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (containsClassesInside(child1) || (child2 != child1 && containsClassesInside(child2))) {
|
|
||||||
myModificationTracker.incCounter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e: PsiInvalidElementAccessException) {
|
|
||||||
myModificationTracker.incCounter() // Shall not happen actually, just a pre-release paranoia
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener")
|
private fun incOutOfBlockModificationCount(file: KtFile) {
|
||||||
|
val count = file.getUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT) ?: 0
|
||||||
private fun containsClassesInside(element: PsiElement?): Boolean {
|
file.putUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT, count + 1)
|
||||||
if (element == null) return false
|
|
||||||
if (element is PsiClass) return true
|
|
||||||
|
|
||||||
var child = element.firstChild
|
|
||||||
while (child != null) {
|
|
||||||
if (containsClassesInside(child)) return true
|
|
||||||
child = child.nextSibling
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInsideCodeBlock(element: PsiElement?): Boolean {
|
private fun isInsideCodeBlock(element: PsiElement): Boolean {
|
||||||
if (element is PsiFileSystemItem) return false
|
|
||||||
if (element == null || element.parent == null) return true
|
|
||||||
|
|
||||||
//TODO: other types
|
//TODO: other types
|
||||||
val blockDeclaration = KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) ?: return false
|
val blockDeclaration = KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) ?: return false
|
||||||
if (blockDeclaration.parents.any { it !is KtClassBody && it !is KtClassOrObject && it !is KtFile }) return false // should not be local declaration
|
if (blockDeclaration.parents.any { it !is KtClassBody && it !is KtClassOrObject && it !is KtFile }) return false // should not be local declaration
|
||||||
@@ -149,3 +106,8 @@ class KotlinCodeBlockModificationListener(modificationTracker: PsiModificationTr
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val FILE_OUT_OF_BLOCK_MODIFICATION_COUNT = Key<Long>("FILE_OUT_OF_BLOCK_MODIFICATION_COUNT")
|
||||||
|
|
||||||
|
val KtFile.outOfBlockModificationCount: Long
|
||||||
|
get() = getUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT) ?: 0
|
||||||
|
|||||||
@@ -112,3 +112,11 @@ inline fun <T, R : Any> Iterable<T>.firstNotNullResult(transform: (T) -> R?): R?
|
|||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long {
|
||||||
|
var sum: Long = 0
|
||||||
|
for (element in this) {
|
||||||
|
sum += selector(element)
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|||||||
+11
-10
@@ -19,12 +19,14 @@ package org.jetbrains.kotlin.idea.caches.resolve
|
|||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||||
|
import com.intellij.openapi.util.ModificationTracker
|
||||||
import com.intellij.psi.util.CachedValue
|
import com.intellij.psi.util.CachedValue
|
||||||
import com.intellij.psi.util.CachedValueProvider
|
import com.intellij.psi.util.CachedValueProvider
|
||||||
import com.intellij.psi.util.CachedValuesManager
|
import com.intellij.psi.util.CachedValuesManager
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
import com.intellij.psi.util.PsiModificationTracker
|
||||||
import com.intellij.util.containers.SLRUCache
|
import com.intellij.util.containers.SLRUCache
|
||||||
import org.jetbrains.kotlin.analyzer.EmptyResolverForProject
|
import org.jetbrains.kotlin.analyzer.EmptyResolverForProject
|
||||||
|
import org.jetbrains.kotlin.asJava.outOfBlockModificationCount
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||||
import org.jetbrains.kotlin.container.getService
|
import org.jetbrains.kotlin.container.getService
|
||||||
@@ -40,6 +42,7 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
|
|||||||
import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
|
import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
|
||||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
|
||||||
import org.jetbrains.kotlin.utils.keysToMap
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
|
|
||||||
internal val LOG = Logger.getInstance(KotlinCacheService::class.java)
|
internal val LOG = Logger.getInstance(KotlinCacheService::class.java)
|
||||||
@@ -92,10 +95,10 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
|||||||
// we assume that all files come from the same module
|
// we assume that all files come from the same module
|
||||||
val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single()
|
val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single()
|
||||||
val syntheticFileModule = files.map { it.getModuleInfo() }.toSet().single()
|
val syntheticFileModule = files.map { it.getModuleInfo() }.toSet().single()
|
||||||
val dependenciesForSyntheticFileCache = listOf(
|
val filesModificationTracker = ModificationTracker {
|
||||||
PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT,
|
files.sumByLong { it.outOfBlockModificationCount }
|
||||||
KotlinOutOfBlockCompletionModificationTracker.getInstance(project)
|
}
|
||||||
)
|
val dependenciesForSyntheticFileCache = listOf(PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, filesModificationTracker)
|
||||||
val debugName = "completion/highlighting in $syntheticFileModule for files ${files.joinToString { it.name }} for platform $targetPlatform"
|
val debugName = "completion/highlighting in $syntheticFileModule for files ${files.joinToString { it.name }} for platform $targetPlatform"
|
||||||
return when {
|
return when {
|
||||||
syntheticFileModule is ModuleSourceInfo -> {
|
syntheticFileModule is ModuleSourceInfo -> {
|
||||||
@@ -179,19 +182,17 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService {
|
|||||||
|
|
||||||
private val syntheticFileCachesLock = Any()
|
private val syntheticFileCachesLock = Any()
|
||||||
|
|
||||||
private val slruCacheProvider = CachedValueProvider {
|
private val syntheticFilesCacheProvider = CachedValueProvider {
|
||||||
CachedValueProvider.Result(object : SLRUCache<Set<KtFile>, ProjectResolutionFacade>(2, 3) {
|
CachedValueProvider.Result(object : SLRUCache<Set<KtFile>, ProjectResolutionFacade>(2, 3) {
|
||||||
override fun createValue(files: Set<KtFile>): ProjectResolutionFacade {
|
override fun createValue(files: Set<KtFile>) = createFacadeForSyntheticFiles(files)
|
||||||
return createFacadeForSyntheticFiles(files)
|
|
||||||
}
|
|
||||||
}, LibraryModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project))
|
}, LibraryModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFacadeForSyntheticFiles(files: Set<KtFile>): ProjectResolutionFacade {
|
private fun getFacadeForSyntheticFiles(files: Set<KtFile>): ProjectResolutionFacade {
|
||||||
return synchronized(syntheticFileCachesLock) {
|
synchronized(syntheticFileCachesLock) {
|
||||||
//NOTE: computations inside createCacheForSyntheticFiles depend on project root structure
|
//NOTE: computations inside createCacheForSyntheticFiles depend on project root structure
|
||||||
// so we additionally drop the whole slru cache on change
|
// so we additionally drop the whole slru cache on change
|
||||||
CachedValuesManager.getManager(project).getCachedValue(project, slruCacheProvider).get(files)
|
return CachedValuesManager.getManager(project).getCachedValue(project, syntheticFilesCacheProvider).get(files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
class KotlinOutOfBlockCompletionModificationTracker() : SimpleModificationTracker() {
|
|
||||||
companion object {
|
|
||||||
fun getInstance(project: Project): KotlinOutOfBlockCompletionModificationTracker
|
|
||||||
= ServiceManager.getService(project, KotlinOutOfBlockCompletionModificationTracker::class.java)!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun performCompletionWithOutOfBlockTracking(completionPosition: PsiElement, body: () -> Unit) {
|
|
||||||
if (KotlinCodeBlockModificationListener.isInsideCodeBlock(completionPosition)) {
|
|
||||||
body()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
body()
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
KotlinOutOfBlockCompletionModificationTracker.getInstance(completionPosition.project).incModificationCount()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-8
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
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.idea.completion.smart.SmartCompletion
|
||||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionSession
|
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionSession
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -254,17 +253,13 @@ class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
val context = position.getUserData(CompletionContext.COMPLETION_CONTEXT_KEY)!!
|
val context = position.getUserData(CompletionContext.COMPLETION_CONTEXT_KEY)!!
|
||||||
val correctedOffset = context.offsetMap.getOffset(STRING_TEMPLATE_AFTER_DOT_REAL_START_OFFSET)
|
val correctedOffset = context.offsetMap.getOffset(STRING_TEMPLATE_AFTER_DOT_REAL_START_OFFSET)
|
||||||
val correctedParameters = parameters.withPosition(correctedPosition, correctedOffset)
|
val correctedParameters = parameters.withPosition(correctedPosition, correctedOffset)
|
||||||
performCompletionWithOutOfBlockTracking(position) {
|
doComplete(correctedParameters, toFromOriginalFileMapper, result,
|
||||||
doComplete(correctedParameters, toFromOriginalFileMapper, result,
|
lookupElementPostProcessor = { wrapLookupElementForStringTemplateAfterDotCompletion(it) })
|
||||||
lookupElementPostProcessor = { wrapLookupElementForStringTemplateAfterDotCompletion(it) })
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
performCompletionWithOutOfBlockTracking(position) {
|
doComplete(parameters, toFromOriginalFileMapper, result)
|
||||||
doComplete(parameters, toFromOriginalFileMapper, result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doComplete(
|
private fun doComplete(
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
<component>
|
<component>
|
||||||
<implementation-class>org.jetbrains.kotlin.idea.completion.LookupCancelWatcher</implementation-class>
|
<implementation-class>org.jetbrains.kotlin.idea.completion.LookupCancelWatcher</implementation-class>
|
||||||
</component>
|
</component>
|
||||||
|
<component>
|
||||||
|
<implementation-class>org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener</implementation-class>
|
||||||
|
</component>
|
||||||
</project-components>
|
</project-components>
|
||||||
|
|
||||||
<application-components>
|
<application-components>
|
||||||
@@ -264,9 +267,6 @@
|
|||||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker"
|
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker"
|
||||||
serviceImplementation="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"
|
<projectService serviceInterface="org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade"
|
||||||
serviceImplementation="org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade"/>
|
serviceImplementation="org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade"/>
|
||||||
|
|
||||||
@@ -583,8 +583,6 @@
|
|||||||
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider"/>
|
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.versions.UnsupportedAbiVersionNotificationPanelProvider"/>
|
||||||
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.configuration.KotlinSetupEnvironmentNotificationProvider"/>
|
<editorNotificationProvider implementation="org.jetbrains.kotlin.idea.configuration.KotlinSetupEnvironmentNotificationProvider"/>
|
||||||
|
|
||||||
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener"/>
|
|
||||||
|
|
||||||
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearcher"/>
|
<referencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearcher"/>
|
||||||
<directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>
|
<directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>
|
||||||
<overridingMethodsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodsWithGenericsSearcher"/>
|
<overridingMethodsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodsWithGenericsSearcher"/>
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.KotlinOutOfBlockCompletionModificationTracker
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
||||||
import org.jetbrains.kotlin.idea.conversion.copy.range
|
import org.jetbrains.kotlin.idea.conversion.copy.range
|
||||||
@@ -66,9 +65,6 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
|
|||||||
|
|
||||||
if (modificationStamp == file.modificationStamp) break
|
if (modificationStamp == file.modificationStamp) break
|
||||||
|
|
||||||
//TODO: it's a hack!
|
|
||||||
KotlinOutOfBlockCompletionModificationTracker.getInstance(file.project).incModificationCount()
|
|
||||||
|
|
||||||
elementToActions = collectAvailableActions(file, rangeMarker)
|
elementToActions = collectAvailableActions(file, rangeMarker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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
|
||||||
|
|
||||||
|
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.util.getFileResolutionScope
|
||||||
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||||
|
|
||||||
|
class DummyFileResolveCachingTest : LightCodeInsightFixtureTestCase() {
|
||||||
|
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
myFixture.configureByText(KotlinFileType.INSTANCE, "")
|
||||||
|
|
||||||
|
val dummyFileText = "import java.util.ArrayList"
|
||||||
|
val dummyFile = KtPsiFactory(project).createAnalyzableFile("Dummy.kt", dummyFileText, file)
|
||||||
|
|
||||||
|
dummyFile.getResolutionFacade().getFileResolutionScope(dummyFile)
|
||||||
|
|
||||||
|
dummyFile.importDirectives.single().delete()
|
||||||
|
|
||||||
|
val resolutionScope = dummyFile.getResolutionFacade().getFileResolutionScope(dummyFile)
|
||||||
|
val classifier = resolutionScope.findClassifier(Name.identifier("ArrayList"), NoLookupLocation.FROM_IDE)
|
||||||
|
assertNull(classifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user