diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCache.kt index 862d4c052e1..56d936210b3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCache.kt @@ -52,14 +52,21 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() private val LOG = Logger.getInstance(KotlinShortNamesCache::class.java) } + //hacky way to avoid searches for Kotlin classes, when looking for Java (from Kotlin) + val disableSearch: ThreadLocal = object : ThreadLocal() { + override fun initialValue(): Boolean = false + } + //region Classes override fun processAllClassNames(processor: Processor): Boolean { + if (disableSearch.get()) return true return KotlinClassShortNameIndex.getInstance().processAllKeys(project, processor) && KotlinFileFacadeShortNameIndex.INSTANCE.processAllKeys(project, processor) } override fun processAllClassNames(processor: Processor, scope: GlobalSearchScope, filter: IdFilter?): Boolean { + if (disableSearch.get()) return true return processAllClassNames(processor) } @@ -67,6 +74,7 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() * Return kotlin class names from project sources which should be visible from java. */ override fun getAllClassNames(): Array { + if (disableSearch.get()) return ArrayUtil.EMPTY_STRING_ARRAY return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor -> processAllClassNames(processor) } @@ -78,6 +86,7 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() scope: GlobalSearchScope, filter: IdFilter? ): Boolean { + if (disableSearch.get()) return true val effectiveScope = kotlinDeclarationsVisibleFromJavaScope(scope) val fqNameProcessor = Processor { fqName: FqName? -> if (fqName == null) return@Processor true @@ -131,6 +140,7 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() * Return class names form kotlin sources in given scope which should be visible as Java classes. */ override fun getClassesByName(name: String, scope: GlobalSearchScope): Array { + if (disableSearch.get()) return PsiClass.EMPTY_ARRAY return withArrayProcessor(PsiClass.EMPTY_ARRAY) { processor -> processClassesWithName(name, processor, scope, null) } @@ -150,16 +160,19 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() //region Methods override fun processAllMethodNames(processor: Processor, scope: GlobalSearchScope, filter: IdFilter?): Boolean { + if (disableSearch.get()) return true return processAllMethodNames(processor) } override fun getAllMethodNames(): Array { + if (disableSearch.get()) ArrayUtil.EMPTY_STRING_ARRAY return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor -> processAllMethodNames(processor) } } private fun processAllMethodNames(processor: Processor): Boolean { + if (disableSearch.get()) return true if (!KotlinFunctionShortNameIndex.getInstance().processAllKeys(project, processor)) { return false } @@ -175,6 +188,7 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() scope: GlobalSearchScope, filter: IdFilter? ): Boolean { + if (disableSearch.get()) return true val allFunctionsProcessed = StubIndex.getInstance().processElements( KotlinFunctionShortNameIndex.getInstance().key, name, @@ -220,12 +234,14 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() } override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array { + if (disableSearch.get()) return PsiMethod.EMPTY_ARRAY return withArrayProcessor(PsiMethod.EMPTY_ARRAY) { processor -> processMethodsWithName(name, processor, scope, null) } } override fun getMethodsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array { + if (disableSearch.get()) return PsiMethod.EMPTY_ARRAY require(maxCount >= 0) return withArrayProcessor(PsiMethod.EMPTY_ARRAY) { processor -> @@ -240,23 +256,28 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() } } - override fun processMethodsWithName(name: String, scope: GlobalSearchScope, processor: Processor): Boolean = - ContainerUtil.process(getMethodsByName(name, scope), processor) + override fun processMethodsWithName(name: String, scope: GlobalSearchScope, processor: Processor): Boolean { + if (disableSearch.get()) return true + return ContainerUtil.process(getMethodsByName(name, scope), processor) + } //endregion //region Fields override fun processAllFieldNames(processor: Processor, scope: GlobalSearchScope, filter: IdFilter?): Boolean { + if (disableSearch.get()) return true return processAllFieldNames(processor) } override fun getAllFieldNames(): Array { + if (disableSearch.get()) return ArrayUtil.EMPTY_STRING_ARRAY return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor -> processAllFieldNames(processor) } } private fun processAllFieldNames(processor: Processor): Boolean { + if (disableSearch.get()) return true return KotlinPropertyShortNameIndex.getInstance().processAllKeys(project, processor) } @@ -266,6 +287,7 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() scope: GlobalSearchScope, filter: IdFilter? ): Boolean { + if (disableSearch.get()) return true return StubIndex.getInstance().processElements( KotlinPropertyShortNameIndex.getInstance().key, name, @@ -282,12 +304,14 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() } override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array { + if (disableSearch.get()) return PsiField.EMPTY_ARRAY return withArrayProcessor(PsiField.EMPTY_ARRAY) { processor -> processFieldsWithName(name, processor, scope, null) } } override fun getFieldsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array { + if (disableSearch.get()) return PsiField.EMPTY_ARRAY require(maxCount >= 0) return withArrayProcessor(PsiField.EMPTY_ARRAY) { processor -> diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt index b81c58ace9f..9e65e8f7663 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/AllClassesCompletion.kt @@ -21,10 +21,12 @@ import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.psi.PsiClass import com.intellij.psi.PsiLiteral +import com.intellij.psi.search.PsiShortNamesCache import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters +import org.jetbrains.kotlin.idea.caches.KotlinShortNamesCache import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper import org.jetbrains.kotlin.idea.core.isJavaClassNotToBeUsedInKotlin import org.jetbrains.kotlin.idea.project.TargetPlatformDetector @@ -86,21 +88,29 @@ class AllClassesCompletion(private val parameters: CompletionParameters, } private fun addAdaptedJavaCompletion(collector: (PsiClass) -> Unit) { - AllClassesGetter.processJavaClasses(parameters, prefixMatcher, true, { psiClass -> - if (psiClass!! !is KtLightClass) { // Kotlin class should have already been added as kotlin element before - if (psiClass.isSyntheticKotlinClass()) return@processJavaClasses // filter out synthetic classes produced by Kotlin compiler + val shortNamesCache = PsiShortNamesCache.EP_NAME.getExtensions(parameters.editor.project).firstOrNull { + it is KotlinShortNamesCache + } as KotlinShortNamesCache? + shortNamesCache?.disableSearch?.set(true) + try { + AllClassesGetter.processJavaClasses(parameters, prefixMatcher, true) { psiClass -> + if (psiClass!! !is KtLightClass) { // Kotlin class should have already been added as kotlin element before + if (psiClass.isSyntheticKotlinClass()) return@processJavaClasses // filter out synthetic classes produced by Kotlin compiler - val kind = when { - psiClass.isAnnotationType -> ClassKind.ANNOTATION_CLASS - psiClass.isInterface -> ClassKind.INTERFACE - psiClass.isEnum -> ClassKind.ENUM_CLASS - else -> ClassKind.CLASS - } - if (kindFilter(kind) && !isNotToBeUsed(psiClass)) { - collector(psiClass) + val kind = when { + psiClass.isAnnotationType -> ClassKind.ANNOTATION_CLASS + psiClass.isInterface -> ClassKind.INTERFACE + psiClass.isEnum -> ClassKind.ENUM_CLASS + else -> ClassKind.CLASS + } + if (kindFilter(kind) && !isNotToBeUsed(psiClass)) { + collector(psiClass) + } } } - }) + } finally { + shortNamesCache?.disableSearch?.set(false) + } } private fun PsiClass.isSyntheticKotlinClass(): Boolean {