diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt index 813a4a8907b..9e8754fbdc4 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt @@ -16,14 +16,12 @@ package org.jetbrains.kotlin.asJava -import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.psi.* import com.intellij.psi.impl.java.stubs.PsiClassStub import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.PsiFileStub import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.PsiTreeUtil -import com.intellij.util.SmartList import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.elements.* import org.jetbrains.kotlin.asJava.finder.JavaElementFinder @@ -31,6 +29,7 @@ import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.utils.addToStdlib.sequenceOfLazyValues object LightClassUtil { @@ -53,9 +52,11 @@ object LightClassUtil { fun getLightClassAccessorMethods(accessor: KtPropertyAccessor): List { val property = accessor.getNonStrictParentOfType() ?: return emptyList() - val wrappers = getPsiMethodWrappers(property, true) - return wrappers.filter { wrapper -> (accessor.isGetter && !JvmAbi.isSetterName(wrapper.name)) || - (accessor.isSetter && JvmAbi.isSetterName(wrapper.name)) } + val wrappers = getPsiMethodWrappers(property) + return wrappers.filter { wrapper -> + (accessor.isGetter && !JvmAbi.isSetterName(wrapper.name)) || + (accessor.isSetter && JvmAbi.isSetterName(wrapper.name)) + }.toList() } fun getLightFieldForCompanionObject(companionObject: KtClassOrObject): PsiField? { @@ -120,36 +121,16 @@ object LightClassUtil { } fun getLightClassMethods(function: KtFunction): List { - return getPsiMethodWrappers(function, true) + return getPsiMethodWrappers(function).toList() } private fun getPsiMethodWrapper(declaration: KtDeclaration): PsiMethod? { - return getPsiMethodWrappers(declaration, false).firstOrNull() + return getPsiMethodWrappers(declaration).firstOrNull() } - private fun getPsiMethodWrappers(declaration: KtDeclaration, collectAll: Boolean): List { - val psiClass = getWrappingClass(declaration) ?: return emptyList() - - val methods = SmartList() - for (method in psiClass.methods.asList()) { - try { - if (method is KtLightMethod && method.kotlinOrigin === declaration) { - methods.add(method) - if (!collectAll) { - return methods - } - } - } - catch (e: ProcessCanceledException) { - throw e - } - catch (e: Throwable) { - throw IllegalStateException( - "Error while wrapping declaration " + declaration.name + "Context\n:" + method, e) - } - } - - return methods + private fun getPsiMethodWrappers(declaration: KtDeclaration): Sequence { + return getWrappingClasses(declaration).flatMap { it.methods.asSequence() } + .filter { method -> method is KtLightMethod && method.kotlinOrigin === declaration } } private fun getWrappingClass(declaration: KtDeclaration): PsiClass? { @@ -185,6 +166,15 @@ object LightClassUtil { return null } + private fun getWrappingClasses(declaration: KtDeclaration): Sequence { + val wrapperClass = getWrappingClass(declaration) ?: return emptySequence() + val wrapperClassOrigin = (wrapperClass as KtLightClass).kotlinOrigin + if (wrapperClassOrigin is KtObjectDeclaration && wrapperClassOrigin.isCompanion()) { + return sequenceOfLazyValues({ wrapperClass }, { wrapperClass.parent as PsiClass }) + } + return sequenceOf(wrapperClass) + } + fun canGenerateLightClass(declaration: KtDeclaration): Boolean { //noinspection unchecked return PsiTreeUtil.getParentOfType(declaration, KtFunction::class.java, KtProperty::class.java) == null @@ -197,7 +187,7 @@ object LightClassUtil { var setterWrapper = specialSetter val additionalAccessors = arrayListOf() - for (wrapper in getPsiMethodWrappers(ktDeclaration, true)) { + for (wrapper in getPsiMethodWrappers(ktDeclaration)) { if (wrapper !is KtLightMethod) continue if (wrapper.isSetter) { @@ -209,7 +199,7 @@ object LightClassUtil { } } else { - if (getterWrapper == null || getterWrapper == specialGetter) { + if (getterWrapper == null || getterWrapper === specialGetter) { getterWrapper = wrapper } else { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt index 34abaca4364..56f4977cac0 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt @@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiField import com.intellij.psi.PsiNamedElement import com.intellij.psi.impl.PsiVariableEx +import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement @@ -31,4 +32,6 @@ interface KtLightElement : PsiNamedElemen interface KtLightDeclaration: KtLightElement -interface KtLightField : PsiField, KtLightDeclaration, PsiVariableEx \ No newline at end of file +interface KtLightField : PsiField, KtLightDeclaration, PsiVariableEx { + val lightMemberOrigin: LightMemberOrigin? +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightFieldImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightFieldImpl.kt index 341d8f7e3f7..728b8dd98d5 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightFieldImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightFieldImpl.kt @@ -16,6 +16,9 @@ package org.jetbrains.kotlin.asJava.elements +import com.intellij.navigation.ItemPresentation +import com.intellij.navigation.ItemPresentationProviders +import com.intellij.navigation.NavigationItem import com.intellij.openapi.util.TextRange import com.intellij.psi.* import com.intellij.psi.impl.PsiVariableEx @@ -30,10 +33,11 @@ import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtNamedDeclaration +import java.lang.UnsupportedOperationException // Copied from com.intellij.psi.impl.light.LightField sealed class KtLightFieldImpl( - private val lightMemberOrigin: LightMemberOrigin?, + override val lightMemberOrigin: LightMemberOrigin?, override val clsDelegate: PsiField, private val containingClass: KtLightClass ) : LightElement(clsDelegate.manager, KotlinLanguage.INSTANCE), KtLightField { @@ -44,6 +48,8 @@ sealed class KtLightFieldImpl( override fun getUseScope() = kotlinOrigin?.useScope ?: super.getUseScope() + override fun getPresentation(): ItemPresentation? = (kotlinOrigin ?: this).let { ItemPresentationProviders.getItemPresentation(it) } + override fun getName() = clsDelegate.name override fun getNameIdentifier() = lightIdentifier @@ -92,6 +98,20 @@ sealed class KtLightFieldImpl( override fun toString(): String = "${this.javaClass.simpleName}:$name" + override fun equals(other: Any?): Boolean = + other is KtLightField && + name == other.name && + lightMemberOrigin == other.lightMemberOrigin && + containingClass == other.containingClass && + clsDelegate == other.clsDelegate + + override fun hashCode(): Int { + var result = lightMemberOrigin?.hashCode() ?: 0 + result = 31 * result + clsDelegate.hashCode() + result = 31 * result + containingClass.hashCode() + return result + } + override val kotlinOrigin: KtDeclaration? get() = lightMemberOrigin?.originalElement override fun getNavigationElement() = kotlinOrigin ?: super.getNavigationElement() @@ -111,6 +131,7 @@ sealed class KtLightFieldImpl( override fun copy() = Factory.create(lightMemberOrigin?.copy(), clsDelegate, containingClass) + class KtLightEnumConstant( origin: LightMemberOrigin?, override val clsDelegate: PsiEnumConstant, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt index ea92df91a9a..7e4f78b0d6d 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt @@ -182,4 +182,8 @@ fun accessorNameByPropertyName(name: String, accessor: KtLightMethod): String? { JvmAbi.isSetterName(methodName) -> JvmAbi.setterName(name) else -> null } +} + +fun getAccessorNamesCandidatesByPropertyName(name: String): List { + return listOf(JvmAbi.setterName(name), JvmAbi.getterName(name)) } \ No newline at end of file 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 ab7a8ce98c2..ace5b4b204a 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 @@ -25,14 +25,17 @@ import com.intellij.psi.search.PsiShortNamesCache import com.intellij.util.Processor import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.HashSet +import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.defaultImplsChild import org.jetbrains.kotlin.asJava.finder.JavaElementFinder +import org.jetbrains.kotlin.asJava.getAccessorNamesCandidatesByPropertyName import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName -import org.jetbrains.kotlin.idea.stubindex.KotlinClassShortNameIndex -import org.jetbrains.kotlin.idea.stubindex.KotlinFileFacadeShortNameIndex -import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope +import org.jetbrains.kotlin.idea.stubindex.* import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.sequenceOfLazyValues import java.util.* class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() { @@ -85,30 +88,79 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() dest.addAll(allClassNames) } - override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array - = emptyArray() + override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array { + return getMethodSequenceByName(name, scope).toList().toTypedArray() + } - override fun getMethodsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array - = emptyArray() + fun getMethodSequenceByName(name: String, scope: GlobalSearchScope): Sequence { + val propertiesIndex = KotlinPropertyShortNameIndex.getInstance() + val functionIndex = KotlinFunctionShortNameIndex.getInstance() - override fun getFieldsByNameIfNotMoreThan(s: String, scope: GlobalSearchScope, i: Int): Array - = emptyArray() + val kotlinFunctionsPsi = functionIndex.get(name, project, scope).asSequence() + .flatMap { LightClassUtil.getLightClassMethods(it).asSequence() } + .filter { it.name == name } + + val propertyAccessorsPsi = sequenceOfLazyValues({ getPropertyNamesCandidatesByAccessorName(Name.identifier(name)) }) + .flatMap { it.asSequence() } + .flatMap { propertiesIndex.get(it.asString(), project, scope).asSequence() } + .flatMap { LightClassUtil.getLightClassPropertyMethods(it).allDeclarations.asSequence() } + .filter { it.name == name } + .map { it as? PsiMethod } + + return sequenceOfLazyValues({ kotlinFunctionsPsi }, { propertyAccessorsPsi }).flatMap { it }.filterNotNull() + } + + override fun getMethodsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array { + require(maxCount >= 0) + val psiMethods = getMethodSequenceByName(name, scope) + val limitedByMaxCount = psiMethods.take(maxCount).toList() + if (limitedByMaxCount.size == 0) + return PsiMethod.EMPTY_ARRAY + return limitedByMaxCount.toTypedArray() + } + + override fun getFieldsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array { + require(maxCount >= 0) + val psiFields = getFieldSequenceByName(name, scope) + val limitedByMaxCount = psiFields.take(maxCount).toList() + if (limitedByMaxCount.size == 0) + return PsiField.EMPTY_ARRAY + return limitedByMaxCount.toTypedArray() + } override fun processMethodsWithName(name: String, scope: GlobalSearchScope, processor: Processor): Boolean = ContainerUtil.process(getMethodsByName(name, scope), processor) - override fun getAllMethodNames(): Array - = emptyArray() + override fun getAllMethodNames(): Array { + val functionIndex = KotlinFunctionShortNameIndex.getInstance() + val functionNames = functionIndex.getAllKeys(project) + + val propertiesIndex = KotlinPropertyShortNameIndex.getInstance() + val propertyAccessorNames = propertiesIndex.getAllKeys(project) + .flatMap(::getAccessorNamesCandidatesByPropertyName) + + return (functionNames + propertyAccessorNames).toTypedArray() + } override fun getAllMethodNames(set: HashSet) { + set.addAll(allMethodNames) } - override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array - = emptyArray() + fun getFieldSequenceByName(name: String, scope: GlobalSearchScope): Sequence { + return KotlinPropertyShortNameIndex.getInstance().get(name, project, scope).asSequence() + .map { LightClassUtil.getLightClassBackingField(it) } + .filterNotNull() + } - override fun getAllFieldNames(): Array - = emptyArray() + override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array { + return getFieldSequenceByName(name, scope).toList().toTypedArray() + } + + override fun getAllFieldNames(): Array { + return KotlinPropertyShortNameIndex.getInstance().getAllKeys(project).toTypedArray() + } override fun getAllFieldNames(set: HashSet) { + set.addAll(allFieldNames) } } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index e0ee84d89ef..c03f0b1429f 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -18,18 +18,24 @@ package org.jetbrains.kotlin.idea.core import com.intellij.codeInsight.JavaProjectCodeInsightSettings import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFile import com.intellij.psi.PsiMember import com.intellij.psi.PsiModifier +import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.PsiShortNamesCache import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.util.indexing.IdFilter +import org.jetbrains.kotlin.asJava.elements.KtLightElement import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.caches.resolve.* import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension +import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.idea.search.excludeKotlinSources import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.stubindex.* import org.jetbrains.kotlin.idea.util.CallType @@ -59,6 +65,7 @@ class KotlinIndicesHelper( private val moduleDescriptor = resolutionFacade.moduleDescriptor private val project = resolutionFacade.project + private val scopeWithoutKotlin = scope.excludeKotlinSources() as GlobalSearchScope private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@ { if (it.isHiddenInResolution()) return@filter false @@ -202,9 +209,10 @@ class KotlinIndicesHelper( } fun getJvmCallablesByName(name: String): Collection { - val javaDeclarations = PsiShortNamesCache.getInstance(project).getFieldsByName(name, scope).asSequence() + - PsiShortNamesCache.getInstance(project).getMethodsByName(name, scope).asSequence() + val javaDeclarations = PsiShortNamesCache.getInstance(project).getFieldsByName(name, scopeWithoutKotlin).asSequence() + + PsiShortNamesCache.getInstance(project).getMethodsByName(name, scopeWithoutKotlin).asSequence() return javaDeclarations + .filterNot { it is KtLightElement<*,*> } .mapNotNull { (it as PsiMember).getJavaMemberDescriptor(resolutionFacade) as? CallableDescriptor } .filter(descriptorFilter) .toSet() @@ -298,11 +306,11 @@ class KotlinIndicesHelper( val shortNamesCache = PsiShortNamesCache.getInstance(project) val allMethodNames = hashSetOf() - shortNamesCache.processAllMethodNames({ name -> if (nameFilter(name)) allMethodNames.add(name); true }, scope, idFilter) + shortNamesCache.processAllMethodNames({ name -> if (nameFilter(name)) allMethodNames.add(name); true }, scopeWithoutKotlin, idFilter) for (name in allMethodNames) { ProgressManager.checkCanceled() - for (method in shortNamesCache.getMethodsByName(name, scope)) { + for (method in shortNamesCache.getMethodsByName(name, scopeWithoutKotlin).filterNot { it is KtLightElement<*, *> }) { if (!method.hasModifierProperty(PsiModifier.STATIC)) continue if (filterOutPrivate && method.hasModifierProperty(PsiModifier.PRIVATE)) continue if (method.containingClass?.parent !is PsiFile) continue // only top-level classes @@ -321,11 +329,11 @@ class KotlinIndicesHelper( } val allFieldNames = hashSetOf() - shortNamesCache.processAllFieldNames({ name -> if (nameFilter(name)) allFieldNames.add(name); true }, scope, idFilter) + shortNamesCache.processAllFieldNames({ name -> if (nameFilter(name)) allFieldNames.add(name); true }, scopeWithoutKotlin, idFilter) for (name in allFieldNames) { ProgressManager.checkCanceled() - for (field in shortNamesCache.getFieldsByName(name, scope)) { + for (field in shortNamesCache.getFieldsByName(name, scopeWithoutKotlin).filterNot { it is KtLightElement<*, *> }) { if (!field.hasModifierProperty(PsiModifier.STATIC)) continue if (filterOutPrivate && field.hasModifierProperty(PsiModifier.PRIVATE)) continue val descriptor = field.getJavaFieldDescriptor() ?: continue diff --git a/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt b/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt index e5bca7cf6f1..219d7f6c319 100644 --- a/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt +++ b/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt @@ -24,10 +24,12 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex +import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType import org.jetbrains.kotlin.idea.stubindex.* import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtNamedDeclaration +import org.jetbrains.kotlin.psi.psiUtil.containingClass import java.util.* class KotlinGotoClassContributor : GotoClassContributor { @@ -78,8 +80,14 @@ class KotlinGotoSymbolContributor : ChooseByNameContributor { val noLibrarySourceScope = KotlinSourceFilterScope.projectSourceAndClassFiles(baseScope, project) val result = ArrayList() - result += KotlinFunctionShortNameIndex.getInstance().get(name, project, noLibrarySourceScope) - result += KotlinPropertyShortNameIndex.getInstance().get(name, project, noLibrarySourceScope) + result += KotlinFunctionShortNameIndex.getInstance().get(name, project, noLibrarySourceScope).filter { + val method = LightClassUtil.getLightClassMethod(it) + method == null || it.name != method.name + } + result += KotlinPropertyShortNameIndex.getInstance().get(name, project, noLibrarySourceScope).filter { + LightClassUtil.getLightClassBackingField(it) == null || + it.containingClass()?.isInterface() ?: false + } result += KotlinClassShortNameIndex.getInstance().get(name, project, BuiltInClassesScope(noLibrarySourceScope)) result += KotlinTypeAliasShortNameIndex.getInstance().get(name, project, noLibrarySourceScope) diff --git a/idea/testData/cache/kotlinShortNamesCacheTestData1.kt b/idea/testData/cache/kotlinShortNamesCacheTestData1.kt new file mode 100644 index 00000000000..8bdc3ed919e --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestData1.kt @@ -0,0 +1,22 @@ + +object B1 { + @JvmStatic + fun foobar() {} + + @JvmField + val barfoo = "" +} +object B2 { + @JvmStatic + fun foobar() {} + + @JvmField + val barfoo = "" +} +object B3 { + @JvmStatic + fun foobar() {} + + @JvmField + val barfoo = "" +} \ No newline at end of file diff --git a/idea/testData/cache/kotlinShortNamesCacheTestData2.kt b/idea/testData/cache/kotlinShortNamesCacheTestData2.kt new file mode 100644 index 00000000000..35dcd9ff712 --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestData2.kt @@ -0,0 +1,16 @@ +object B1 { + @JvmField + val foobar = "" + + fun method1(){} + + fun methodInBoth(){} +} + +object B2 { + val barfoo = "" + + fun method2(){} + + fun methodInBoth(){} +} \ No newline at end of file diff --git a/idea/testData/cache/kotlinShortNamesCacheTestDataClasses.kt b/idea/testData/cache/kotlinShortNamesCacheTestDataClasses.kt new file mode 100644 index 00000000000..8ee0501036b --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestDataClasses.kt @@ -0,0 +1,7 @@ +class C1 { + +} + +object O1 { + +} \ No newline at end of file diff --git a/idea/testData/cache/kotlinShortNamesCacheTestDataCustomProperties.kt b/idea/testData/cache/kotlinShortNamesCacheTestDataCustomProperties.kt new file mode 100644 index 00000000000..cf90c43d172 --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestDataCustomProperties.kt @@ -0,0 +1,52 @@ +@file:JvmName("KotlinShortNameCacheTestData") + +var topLevelVar: String + get() { + return "" + } + set(value) { + } + + +object B1 { + @JvmStatic + var staticObjectVar: String + get() { + return "" + } + set(value) { + } + + var nonStaticObjectVar: String + get() { + return "" + } + set(value) { + } +} + +class C1 { + var classVar: String + get() { + return "" + } + set(value) { + } + + companion object { + @JvmStatic + var staticCompanionVar: String + get() { + return "" + } + set(value) { + } + + var nonStaticCompanionVar: String + get() { + return "" + } + set(value) { + } + } +} diff --git a/idea/testData/cache/kotlinShortNamesCacheTestDataDefaultProperties.kt b/idea/testData/cache/kotlinShortNamesCacheTestDataDefaultProperties.kt new file mode 100644 index 00000000000..43f2a068280 --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestDataDefaultProperties.kt @@ -0,0 +1,22 @@ +@file:JvmName("KotlinShortNameCacheTestData") + +var topLevelVar = "" + + +object B1 { + @JvmStatic + var staticObjectVar = "" + + var nonStaticObjectVar = "" +} + +class C1 { + var classVar = "" + + companion object { + @JvmStatic + var staticCompanionVar = "" + + var nonStaticCompanionVar = "" + } +} diff --git a/idea/testData/cache/kotlinShortNamesCacheTestDataFields.kt b/idea/testData/cache/kotlinShortNamesCacheTestDataFields.kt new file mode 100644 index 00000000000..a1e19507b28 --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestDataFields.kt @@ -0,0 +1,17 @@ +@JvmField +var topLevelVar = "" + +object B1 { + @JvmField + var objectVar = "" +} + +class C1 { + @JvmField + var classVar = "" + + companion object { + @JvmField + var companionVar = "" + } +} diff --git a/idea/testData/cache/kotlinShortNamesCacheTestDataMethods.kt b/idea/testData/cache/kotlinShortNamesCacheTestDataMethods.kt new file mode 100644 index 00000000000..1297a53df82 --- /dev/null +++ b/idea/testData/cache/kotlinShortNamesCacheTestDataMethods.kt @@ -0,0 +1,27 @@ + +fun topLevelFunction(){ + +} + +object B1 { + @JvmStatic + fun staticMethodOfObject() { + } + + fun nonStaticMethodOfObject() { + } +} + +class C1 { + fun methodOfClass() { + } + + companion object { + @JvmStatic + fun staticMethodOfCompanion() { + } + + fun nonStaticMethodOfCompanion() { + } + } +} diff --git a/idea/testData/quickfix/autoImports/importKotlinCompanionPropertyAsFieldFromJava.test b/idea/testData/quickfix/autoImports/importKotlinCompanionPropertyAsFieldFromJava.test new file mode 100644 index 00000000000..d0ff4146972 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinCompanionPropertyAsFieldFromJava.test @@ -0,0 +1,47 @@ +// FILE: bar/Foo.before.java +// "Static import constant 'foo.Bar.Companion.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Rename reference +// ACTION: Create field 'foobar' +// ACTION: Create parameter 'foobar' +// ACTION: Create local variable 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + foobar + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + companion object { + @JvmField var foobar = "foobar" + } +} + +// FILE: bar/Foo.after.java +// "Static import constant 'foo.Bar.Companion.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Rename reference +// ACTION: Create field 'foobar' +// ACTION: Create parameter 'foobar' +// ACTION: Create local variable 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.Companion.foobar; + +public class Foo { + public void main() + { + foobar + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinCompanionStaticFunctionFromJava.test b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticFunctionFromJava.test new file mode 100644 index 00000000000..6230b1b4e14 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticFunctionFromJava.test @@ -0,0 +1,43 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + foobar(); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +class Bar { + companion object { + @JvmStatic + fun foobar() { + } + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.foobar; + +public class Foo { + public void main() + { + foobar(); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultGetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultGetterFromJava.test new file mode 100644 index 00000000000..df5cec76906 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultGetterFromJava.test @@ -0,0 +1,41 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + getValue(); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + companion object { + @JvmStatic val value = "foobar"; + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.getValue; + +public class Foo { + public void main() + { + getValue(); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultSetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultSetterFromJava.test new file mode 100644 index 00000000000..5ae9fd6f96c --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultSetterFromJava.test @@ -0,0 +1,41 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + companion object { + @JvmStatic var variable: String; + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.setVariable; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedGetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedGetterFromJava.test new file mode 100644 index 00000000000..b7105c7a202 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedGetterFromJava.test @@ -0,0 +1,43 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + getValue(); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + companion object { + val value = "foobar"; + @JvmStatic get() { + } + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.getValue; + +public class Foo { + public void main() + { + getValue(); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedSetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedSetterFromJava.test new file mode 100644 index 00000000000..5d05eb02466 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedSetterFromJava.test @@ -0,0 +1,44 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + companion object { + var variable: String; + @JvmStatic set(value) { + field = value + } + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.setVariable; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinPropertyAsFieldFromJava.test b/idea/testData/quickfix/autoImports/importKotlinPropertyAsFieldFromJava.test new file mode 100644 index 00000000000..a7c6e4910a4 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinPropertyAsFieldFromJava.test @@ -0,0 +1,45 @@ +// FILE: bar/Foo.before.java +// "Static import constant 'foo.Bar.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Rename reference +// ACTION: Create field 'foobar' +// ACTION: Create parameter 'foobar' +// ACTION: Create local variable 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + foobar + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + @JvmField var foobar = "foobar" +} + +// FILE: bar/Foo.after.java +// "Static import constant 'foo.Bar.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Rename reference +// ACTION: Create field 'foobar' +// ACTION: Create parameter 'foobar' +// ACTION: Create local variable 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.foobar; + +public class Foo { + public void main() + { + foobar + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinStaticFunctionFromJava.test b/idea/testData/quickfix/autoImports/importKotlinStaticFunctionFromJava.test new file mode 100644 index 00000000000..457f472e2f8 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinStaticFunctionFromJava.test @@ -0,0 +1,40 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + foobar(); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + @JvmStatic fun foobar() { + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.foobar'" "true" +// ERROR: Unresolved reference: foobar +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.foobar; + +public class Foo { + public void main() + { + foobar(); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultGetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultGetterFromJava.test new file mode 100644 index 00000000000..2b69d574958 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultGetterFromJava.test @@ -0,0 +1,39 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + getValue(); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + @JvmStatic val value = "foobar"; +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.getValue; + +public class Foo { + public void main() + { + getValue(); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultSetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultSetterFromJava.test new file mode 100644 index 00000000000..22a052154a2 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultSetterFromJava.test @@ -0,0 +1,39 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + @JvmStatic var variable: String; +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.setVariable; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedGetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedGetterFromJava.test new file mode 100644 index 00000000000..e587153e8fb --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedGetterFromJava.test @@ -0,0 +1,41 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + getValue(); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + val value = "foobar"; + @JvmStatic get() { + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.getValue'" "true" +// ERROR: Unresolved reference: getValue +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.getValue; + +public class Foo { + public void main() + { + getValue(); + } +} + + diff --git a/idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedSetterFromJava.test b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedSetterFromJava.test new file mode 100644 index 00000000000..0cf9278165a --- /dev/null +++ b/idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedSetterFromJava.test @@ -0,0 +1,42 @@ +// FILE: bar/Foo.before.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + +// FILE: foo/Bar.dependency.kt +package foo + +object Bar { + var variable: String; + @JvmStatic set(value) { + field = value + } +} + +// FILE: bar/Foo.after.java +// "Static import method 'foo.Bar.setVariable'" "true" +// ERROR: Unresolved reference: setVariable +// ACTION: Create method 'foobar' +// WITH_RUNTIME +package bar; + +import static foo.Bar.setVariable; + +public class Foo { + public void main() + { + setVariable("foobar"); + } +} + + diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCacheTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCacheTest.kt new file mode 100644 index 00000000000..f7cfd73a64c --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/KotlinShortNamesCacheTest.kt @@ -0,0 +1,273 @@ +/* + * 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.caches + +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiModifier +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.PsiShortNamesCache +import com.sun.tools.javac.util.Convert.shortName +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil +import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.test.KotlinTestUtils + +class KotlinShortNamesCacheTest : KotlinCodeInsightTestCase() { + + lateinit var cacheInstance: PsiShortNamesCache + + override fun setUp() { + super.setUp() + cacheInstance = KotlinShortNamesCache(project) + ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, testProjectJdk) + } + + override fun tearDown() { + ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(myModule, testProjectJdk) + super.tearDown() + + } + + override fun getModule() = myModule!! + + fun testGetMethodsByNameIfNotMoreThanLimits() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestData1.kt") + configureByFile(file) + val scope = GlobalSearchScope.allScope(project) + assertSize(2, cacheInstance.getMethodsByNameIfNotMoreThan("foobar", scope, 2)) + assertSize(3, cacheInstance.getMethodsByNameIfNotMoreThan("foobar", scope, 3)) + assertSize(3, cacheInstance.getMethodsByNameIfNotMoreThan("foobar", scope, Int.MAX_VALUE)) + } + + fun testGetFieldsByNameIfNotMoreThanLimits() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestData1.kt") + configureByFile(file) + val scope = GlobalSearchScope.allScope(project) + assertSize(2, cacheInstance.getFieldsByNameIfNotMoreThan("barfoo", scope, 2)) + assertSize(3, cacheInstance.getFieldsByNameIfNotMoreThan("barfoo", scope, 3)) + assertSize(3, cacheInstance.getFieldsByNameIfNotMoreThan("barfoo", scope, Int.MAX_VALUE)) + } + + fun testGetAllFields() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestData2.kt") + configureByFile(file) + val allFieldNameList = cacheInstance.allFieldNames.asList() + assertContainsElements(allFieldNameList, "foobar") + assertContainsElements(allFieldNameList, "barfoo") + } + + fun testGetAllMethods() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestData2.kt") + configureByFile(file) + val allMethodNameList = cacheInstance.allMethodNames.asList() + assertContainsElements(allMethodNameList, "getFoobar") + assertContainsElements(allMethodNameList, "getBarfoo") + assertContainsElements(allMethodNameList, "setFoobar") + assertContainsElements(allMethodNameList, "setBarfoo") + assertContainsElements(allMethodNameList, "method1") + assertContainsElements(allMethodNameList, "method2") + assertContainsElements(allMethodNameList, "methodInBoth") + } + + fun testGetAllClasses() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestDataClasses.kt") + configureByFile(file) + val allClassNameList = cacheInstance.allClassNames.asList() + assertContainsElements(allClassNameList, "C1") + assertContainsElements(allClassNameList, "O1") + } + + fun methodArrayDebugToString(a: Array) + = a.map { "${(it as KtLightMethod).clsDelegate.getKotlinFqName()} static=${it.hasModifierProperty(PsiModifier.STATIC)}" }.joinToString("\n") + + fun accessorArrayDebugToString(a: Array) + = a.map { "${(it as KtLightMethod).clsDelegate.getKotlinFqName()} property=${(it.lightMethodOrigin?.originalElement as KtProperty).fqName} static=${it.hasModifierProperty(PsiModifier.STATIC)}" }.joinToString("\n") + + fun checkMethodFound(methods: Array, stringFqName: String, static: Boolean) { + assertNotNull("Method $stringFqName with static=$static not found\n" + methodArrayDebugToString(methods), + methods.find { + stringFqName == (it as KtLightMethod).clsDelegate.getKotlinFqName().toString() + && + it.hasModifierProperty(PsiModifier.STATIC) == static + }) + } + + fun checkIsSingleMethodFound(scope: GlobalSearchScope, stringFqName: String, static: Boolean, query: String = shortName(stringFqName)) { + cacheInstance.getMethodsByName(query, scope).let { + checkMethodFound(it, stringFqName, static) + assertSize(1, it) + } + } + + fun checkIsSingleMethodFoundCompanion(scope: GlobalSearchScope, delegateFqName: String, originalFqName: String, query: String = shortName(originalFqName)) { + cacheInstance.getMethodsByName(query, scope).let { + checkMethodFound(it, delegateFqName, true) + checkMethodFound(it, originalFqName, false) + assertEquals((it[0] as KtLightMethod).kotlinOrigin, (it[1] as KtLightMethod).kotlinOrigin) + assertSize(2, it) + } + } + + fun checkIsVarAccessorsFound(scope: GlobalSearchScope, stringVarFqName: String, getFqName: String, setFqName: String, static: Boolean) { + val varName = shortName(stringVarFqName) + + cacheInstance.getMethodsByName(JvmAbi.getterName(varName), scope).let { + checkAccessorFound(it, getFqName, stringVarFqName, static) + assertSize(1, it) + } + cacheInstance.getMethodsByName(JvmAbi.setterName(varName), scope).let { + checkAccessorFound(it, setFqName, stringVarFqName, static) + assertSize(1, it) + } + } + + fun checkIsVarAccessorsFound(scope: GlobalSearchScope, stringVarFqName: String, static: Boolean) { + val (getter, setter) = accessorsFqNameStringFor(stringVarFqName) + checkIsVarAccessorsFound(scope, stringVarFqName, getter, setter, static) + } + + fun checkIsVarAccessorsFoundCompanion(scope: GlobalSearchScope, stringVarFqName: String, getterFqName: String, setterFqName: String, + delegateGetterFqName: String, delegateSetterFqName: String) { + val varName = shortName(stringVarFqName) + + + cacheInstance.getMethodsByName(JvmAbi.getterName(varName), scope).let { + checkAccessorFound(it, delegateGetterFqName, stringVarFqName, true) + checkAccessorFound(it, getterFqName, stringVarFqName, false) + assertSize(2, it) + } + cacheInstance.getMethodsByName(JvmAbi.setterName(varName), scope).let { + checkAccessorFound(it, delegateSetterFqName, stringVarFqName, true) + checkAccessorFound(it, setterFqName, stringVarFqName, false) + assertSize(2, it) + } + } + + fun checkIsVarAccessorsFoundCompanion(scope: GlobalSearchScope, stringVarFqName: String) { + val (getter, setter) = accessorsFqNameStringFor(stringVarFqName) + val varFqName = FqName(stringVarFqName) + val varName = varFqName.shortName().asString() + val companionParent = varFqName.parent().parent().asString() + + checkIsVarAccessorsFoundCompanion(scope, stringVarFqName, getter, setter, + companionParent + "." + JvmAbi.getterName(varName), + companionParent + "." + JvmAbi.setterName(varName)) + } + + fun accessorsFqNameStringFor(stringVarFqName: String): Pair { + val varFqName = FqName(stringVarFqName) + val varShortName = varFqName.shortName().asString() + val stringVarParentFqName = varFqName.parent().asString() + return Pair(stringVarParentFqName + "." + JvmAbi.getterName(varShortName), + stringVarParentFqName + "." + JvmAbi.setterName(varShortName)) + } + + fun checkAccessorFound(methods: Array, stringFqName: String, propertyFqName: String, static: Boolean) { + assertNotNull("Accessor $stringFqName property=$propertyFqName static=$static not found\n" + accessorArrayDebugToString(methods), + methods.find { + stringFqName == (it as KtLightMethod).clsDelegate.getKotlinFqName().toString() + && + (it.lightMethodOrigin?.originalElement as KtProperty).fqName?.asString() == propertyFqName + && + it.hasModifierProperty(PsiModifier.STATIC) == static + }) + } + + fun testGetMethodsByNameWithFunctions() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestDataMethods.kt") + configureByFile(file) + val scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(myModule) + checkIsSingleMethodFound(scope, "KotlinShortNamesCacheTestDataMethodsKt.topLevelFunction", true) + checkIsSingleMethodFound(scope, "B1.staticMethodOfObject", true) + checkIsSingleMethodFound(scope, "B1.nonStaticMethodOfObject", false) + checkIsSingleMethodFound(scope, "C1.methodOfClass", false) + checkIsSingleMethodFoundCompanion(scope, "C1.staticMethodOfCompanion", "C1.Companion.staticMethodOfCompanion") + checkIsSingleMethodFound(scope, "C1.Companion.nonStaticMethodOfCompanion", false) + } + + fun doTestGetMethodsByNameWithAccessors(file: String) { + + configureByFile(file) + val scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(myModule) + checkIsVarAccessorsFound(scope, "topLevelVar", "KotlinShortNameCacheTestData.getTopLevelVar", + "KotlinShortNameCacheTestData.setTopLevelVar", true) + + checkIsVarAccessorsFound(scope, "B1.staticObjectVar", true) + checkIsVarAccessorsFound(scope, "B1.nonStaticObjectVar", false) + checkIsVarAccessorsFound(scope, "C1.classVar", false) + checkIsVarAccessorsFoundCompanion(scope, "C1.Companion.staticCompanionVar") + checkIsVarAccessorsFound(scope, "C1.Companion.nonStaticCompanionVar", false) + } + + fun testGetMethodsByNameWithDefaultPropertyAccessors() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestDataDefaultProperties.kt") + doTestGetMethodsByNameWithAccessors(file) + } + + fun testGetMethodsByNameWithCustomPropertyAccessors() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestDataCustomProperties.kt") + doTestGetMethodsByNameWithAccessors(file) + } + + fun checkFieldFound(methods: Array, stringFqName: String, static: Boolean) { + assertNotNull("Field $stringFqName with static=$static not found\n" + fieldArrayDebugToString(methods), + methods.find { + stringFqName == (it as KtLightField).clsDelegate.getKotlinFqName().toString() + && + it.hasModifierProperty(PsiModifier.STATIC) == static + }) + } + + fun fieldArrayDebugToString(a: Array) + = a.map { "${(it as KtLightField).clsDelegate.getKotlinFqName()} property=${(it.kotlinOrigin as KtProperty).fqName} static=${it.hasModifierProperty(PsiModifier.STATIC)}" }.joinToString("\n") + + + fun checkIsSingleFieldFound(scope: GlobalSearchScope, stringFqName: String, static: Boolean, query: String = shortName(stringFqName)) { + cacheInstance.getFieldsByName(query, scope).let { + checkFieldFound(it, stringFqName, static) + assertSize(1, it) + } + } + + fun testGetFieldsByName() { + val file = KotlinTestUtils.navigationMetadata("idea/testData/cache/kotlinShortNamesCacheTestDataFields.kt") + configureByFile(file) + val scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(myModule) + checkIsSingleFieldFound(scope, "KotlinShortNamesCacheTestDataFieldsKt.topLevelVar", true) + checkIsSingleFieldFound(scope, "B1.objectVar", true) + checkIsSingleFieldFound(scope, "C1.classVar", false) + checkIsSingleFieldFound(scope, "C1.companionVar", true) + } + + + override fun getTestProjectJdk(): Sdk? { + return PluginTestCaseBase.mockJdk() + } + + override fun getTestDataPath(): String { + return KotlinTestUtils.getHomeDirectory() + "/" + } + +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 62802c49707..ba96c764a1a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -167,6 +167,78 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } + @TestMetadata("importKotlinCompanionPropertyAsFieldFromJava.test") + public void testImportKotlinCompanionPropertyAsFieldFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinCompanionPropertyAsFieldFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinCompanionStaticFunctionFromJava.test") + public void testImportKotlinCompanionStaticFunctionFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinCompanionStaticFunctionFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinCompanionStaticPropertyDefaultGetterFromJava.test") + public void testImportKotlinCompanionStaticPropertyDefaultGetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultGetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinCompanionStaticPropertyDefaultSetterFromJava.test") + public void testImportKotlinCompanionStaticPropertyDefaultSetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyDefaultSetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinCompanionStaticPropertyOverloadedGetterFromJava.test") + public void testImportKotlinCompanionStaticPropertyOverloadedGetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedGetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinCompanionStaticPropertyOverloadedSetterFromJava.test") + public void testImportKotlinCompanionStaticPropertyOverloadedSetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinCompanionStaticPropertyOverloadedSetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinPropertyAsFieldFromJava.test") + public void testImportKotlinPropertyAsFieldFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinPropertyAsFieldFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinStaticFunctionFromJava.test") + public void testImportKotlinStaticFunctionFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinStaticFunctionFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinStaticPropertyDefaultGetterFromJava.test") + public void testImportKotlinStaticPropertyDefaultGetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultGetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinStaticPropertyDefaultSetterFromJava.test") + public void testImportKotlinStaticPropertyDefaultSetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinStaticPropertyDefaultSetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinStaticPropertyOverloadedGetterFromJava.test") + public void testImportKotlinStaticPropertyOverloadedGetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedGetterFromJava.test"); + doTestWithExtraFile(fileName); + } + + @TestMetadata("importKotlinStaticPropertyOverloadedSetterFromJava.test") + public void testImportKotlinStaticPropertyOverloadedSetterFromJava() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importKotlinStaticPropertyOverloadedSetterFromJava.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("importTrait.before.Main.kt") public void testImportTrait() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importTrait.before.Main.kt");