Return Kotlin fields and methods through KotlinShortNameCache
#KT-12205 Fixed
This commit is contained in:
committed by
Dmitry Jemerov
parent
b06bdcef75
commit
18feb8f622
@@ -16,14 +16,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.asJava
|
package org.jetbrains.kotlin.asJava
|
||||||
|
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.java.stubs.PsiClassStub
|
import com.intellij.psi.impl.java.stubs.PsiClassStub
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.stubs.PsiFileStub
|
import com.intellij.psi.stubs.PsiFileStub
|
||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.util.SmartList
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
import org.jetbrains.kotlin.asJava.elements.*
|
import org.jetbrains.kotlin.asJava.elements.*
|
||||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
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.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.sequenceOfLazyValues
|
||||||
|
|
||||||
object LightClassUtil {
|
object LightClassUtil {
|
||||||
|
|
||||||
@@ -53,9 +52,11 @@ object LightClassUtil {
|
|||||||
|
|
||||||
fun getLightClassAccessorMethods(accessor: KtPropertyAccessor): List<PsiMethod> {
|
fun getLightClassAccessorMethods(accessor: KtPropertyAccessor): List<PsiMethod> {
|
||||||
val property = accessor.getNonStrictParentOfType<KtProperty>() ?: return emptyList()
|
val property = accessor.getNonStrictParentOfType<KtProperty>() ?: return emptyList()
|
||||||
val wrappers = getPsiMethodWrappers(property, true)
|
val wrappers = getPsiMethodWrappers(property)
|
||||||
return wrappers.filter { wrapper -> (accessor.isGetter && !JvmAbi.isSetterName(wrapper.name)) ||
|
return wrappers.filter { wrapper ->
|
||||||
(accessor.isSetter && JvmAbi.isSetterName(wrapper.name)) }
|
(accessor.isGetter && !JvmAbi.isSetterName(wrapper.name)) ||
|
||||||
|
(accessor.isSetter && JvmAbi.isSetterName(wrapper.name))
|
||||||
|
}.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLightFieldForCompanionObject(companionObject: KtClassOrObject): PsiField? {
|
fun getLightFieldForCompanionObject(companionObject: KtClassOrObject): PsiField? {
|
||||||
@@ -120,36 +121,16 @@ object LightClassUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getLightClassMethods(function: KtFunction): List<PsiMethod> {
|
fun getLightClassMethods(function: KtFunction): List<PsiMethod> {
|
||||||
return getPsiMethodWrappers(function, true)
|
return getPsiMethodWrappers(function).toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPsiMethodWrapper(declaration: KtDeclaration): PsiMethod? {
|
private fun getPsiMethodWrapper(declaration: KtDeclaration): PsiMethod? {
|
||||||
return getPsiMethodWrappers(declaration, false).firstOrNull()
|
return getPsiMethodWrappers(declaration).firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPsiMethodWrappers(declaration: KtDeclaration, collectAll: Boolean): List<PsiMethod> {
|
private fun getPsiMethodWrappers(declaration: KtDeclaration): Sequence<PsiMethod> {
|
||||||
val psiClass = getWrappingClass(declaration) ?: return emptyList()
|
return getWrappingClasses(declaration).flatMap { it.methods.asSequence() }
|
||||||
|
.filter { method -> method is KtLightMethod && method.kotlinOrigin === declaration }
|
||||||
val methods = SmartList<PsiMethod>()
|
|
||||||
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 getWrappingClass(declaration: KtDeclaration): PsiClass? {
|
private fun getWrappingClass(declaration: KtDeclaration): PsiClass? {
|
||||||
@@ -185,6 +166,15 @@ object LightClassUtil {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getWrappingClasses(declaration: KtDeclaration): Sequence<PsiClass> {
|
||||||
|
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 {
|
fun canGenerateLightClass(declaration: KtDeclaration): Boolean {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return PsiTreeUtil.getParentOfType(declaration, KtFunction::class.java, KtProperty::class.java) == null
|
return PsiTreeUtil.getParentOfType(declaration, KtFunction::class.java, KtProperty::class.java) == null
|
||||||
@@ -197,7 +187,7 @@ object LightClassUtil {
|
|||||||
var setterWrapper = specialSetter
|
var setterWrapper = specialSetter
|
||||||
val additionalAccessors = arrayListOf<PsiMethod>()
|
val additionalAccessors = arrayListOf<PsiMethod>()
|
||||||
|
|
||||||
for (wrapper in getPsiMethodWrappers(ktDeclaration, true)) {
|
for (wrapper in getPsiMethodWrappers(ktDeclaration)) {
|
||||||
if (wrapper !is KtLightMethod) continue
|
if (wrapper !is KtLightMethod) continue
|
||||||
|
|
||||||
if (wrapper.isSetter) {
|
if (wrapper.isSetter) {
|
||||||
@@ -209,7 +199,7 @@ object LightClassUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (getterWrapper == null || getterWrapper == specialGetter) {
|
if (getterWrapper == null || getterWrapper === specialGetter) {
|
||||||
getterWrapper = wrapper
|
getterWrapper = wrapper
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.PsiField
|
import com.intellij.psi.PsiField
|
||||||
import com.intellij.psi.PsiNamedElement
|
import com.intellij.psi.PsiNamedElement
|
||||||
import com.intellij.psi.impl.PsiVariableEx
|
import com.intellij.psi.impl.PsiVariableEx
|
||||||
|
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
@@ -31,4 +32,6 @@ interface KtLightElement<out T : KtElement, out D : PsiElement> : PsiNamedElemen
|
|||||||
|
|
||||||
interface KtLightDeclaration<out T: KtDeclaration, out D: PsiElement>: KtLightElement<T, D>
|
interface KtLightDeclaration<out T: KtDeclaration, out D: PsiElement>: KtLightElement<T, D>
|
||||||
|
|
||||||
interface KtLightField : PsiField, KtLightDeclaration<KtDeclaration, PsiField>, PsiVariableEx
|
interface KtLightField : PsiField, KtLightDeclaration<KtDeclaration, PsiField>, PsiVariableEx {
|
||||||
|
val lightMemberOrigin: LightMemberOrigin?
|
||||||
|
}
|
||||||
+22
-1
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.asJava.elements
|
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.openapi.util.TextRange
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.PsiVariableEx
|
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.KtDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
import java.lang.UnsupportedOperationException
|
||||||
|
|
||||||
// Copied from com.intellij.psi.impl.light.LightField
|
// Copied from com.intellij.psi.impl.light.LightField
|
||||||
sealed class KtLightFieldImpl(
|
sealed class KtLightFieldImpl(
|
||||||
private val lightMemberOrigin: LightMemberOrigin?,
|
override val lightMemberOrigin: LightMemberOrigin?,
|
||||||
override val clsDelegate: PsiField,
|
override val clsDelegate: PsiField,
|
||||||
private val containingClass: KtLightClass
|
private val containingClass: KtLightClass
|
||||||
) : LightElement(clsDelegate.manager, KotlinLanguage.INSTANCE), KtLightField {
|
) : LightElement(clsDelegate.manager, KotlinLanguage.INSTANCE), KtLightField {
|
||||||
@@ -44,6 +48,8 @@ sealed class KtLightFieldImpl(
|
|||||||
|
|
||||||
override fun getUseScope() = kotlinOrigin?.useScope ?: super.getUseScope()
|
override fun getUseScope() = kotlinOrigin?.useScope ?: super.getUseScope()
|
||||||
|
|
||||||
|
override fun getPresentation(): ItemPresentation? = (kotlinOrigin ?: this).let { ItemPresentationProviders.getItemPresentation(it) }
|
||||||
|
|
||||||
override fun getName() = clsDelegate.name
|
override fun getName() = clsDelegate.name
|
||||||
|
|
||||||
override fun getNameIdentifier() = lightIdentifier
|
override fun getNameIdentifier() = lightIdentifier
|
||||||
@@ -92,6 +98,20 @@ sealed class KtLightFieldImpl(
|
|||||||
|
|
||||||
override fun toString(): String = "${this.javaClass.simpleName}:$name"
|
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 val kotlinOrigin: KtDeclaration? get() = lightMemberOrigin?.originalElement
|
||||||
|
|
||||||
override fun getNavigationElement() = kotlinOrigin ?: super.getNavigationElement()
|
override fun getNavigationElement() = kotlinOrigin ?: super.getNavigationElement()
|
||||||
@@ -111,6 +131,7 @@ sealed class KtLightFieldImpl(
|
|||||||
|
|
||||||
override fun copy() = Factory.create(lightMemberOrigin?.copy(), clsDelegate, containingClass)
|
override fun copy() = Factory.create(lightMemberOrigin?.copy(), clsDelegate, containingClass)
|
||||||
|
|
||||||
|
|
||||||
class KtLightEnumConstant(
|
class KtLightEnumConstant(
|
||||||
origin: LightMemberOrigin?,
|
origin: LightMemberOrigin?,
|
||||||
override val clsDelegate: PsiEnumConstant,
|
override val clsDelegate: PsiEnumConstant,
|
||||||
|
|||||||
@@ -182,4 +182,8 @@ fun accessorNameByPropertyName(name: String, accessor: KtLightMethod): String? {
|
|||||||
JvmAbi.isSetterName(methodName) -> JvmAbi.setterName(name)
|
JvmAbi.isSetterName(methodName) -> JvmAbi.setterName(name)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAccessorNamesCandidatesByPropertyName(name: String): List<String> {
|
||||||
|
return listOf(JvmAbi.setterName(name), JvmAbi.getterName(name))
|
||||||
}
|
}
|
||||||
@@ -25,14 +25,17 @@ import com.intellij.psi.search.PsiShortNamesCache
|
|||||||
import com.intellij.util.Processor
|
import com.intellij.util.Processor
|
||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import com.intellij.util.containers.HashSet
|
import com.intellij.util.containers.HashSet
|
||||||
|
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||||
import org.jetbrains.kotlin.asJava.defaultImplsChild
|
import org.jetbrains.kotlin.asJava.defaultImplsChild
|
||||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||||
|
import org.jetbrains.kotlin.asJava.getAccessorNamesCandidatesByPropertyName
|
||||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinClassShortNameIndex
|
import org.jetbrains.kotlin.idea.stubindex.*
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFileFacadeShortNameIndex
|
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
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.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.sequenceOfLazyValues
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() {
|
class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() {
|
||||||
@@ -85,30 +88,79 @@ class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache()
|
|||||||
dest.addAll(allClassNames)
|
dest.addAll(allClassNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array<PsiMethod>
|
override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array<PsiMethod> {
|
||||||
= emptyArray()
|
return getMethodSequenceByName(name, scope).toList().toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getMethodsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array<PsiMethod>
|
fun getMethodSequenceByName(name: String, scope: GlobalSearchScope): Sequence<PsiMethod> {
|
||||||
= emptyArray()
|
val propertiesIndex = KotlinPropertyShortNameIndex.getInstance()
|
||||||
|
val functionIndex = KotlinFunctionShortNameIndex.getInstance()
|
||||||
|
|
||||||
override fun getFieldsByNameIfNotMoreThan(s: String, scope: GlobalSearchScope, i: Int): Array<PsiField>
|
val kotlinFunctionsPsi = functionIndex.get(name, project, scope).asSequence()
|
||||||
= emptyArray()
|
.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<PsiMethod> {
|
||||||
|
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<PsiField> {
|
||||||
|
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<PsiMethod>): Boolean
|
override fun processMethodsWithName(name: String, scope: GlobalSearchScope, processor: Processor<PsiMethod>): Boolean
|
||||||
= ContainerUtil.process(getMethodsByName(name, scope), processor)
|
= ContainerUtil.process(getMethodsByName(name, scope), processor)
|
||||||
|
|
||||||
override fun getAllMethodNames(): Array<String>
|
override fun getAllMethodNames(): Array<String> {
|
||||||
= emptyArray()
|
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<String>) {
|
override fun getAllMethodNames(set: HashSet<String>) {
|
||||||
|
set.addAll(allMethodNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array<PsiField>
|
fun getFieldSequenceByName(name: String, scope: GlobalSearchScope): Sequence<PsiField> {
|
||||||
= emptyArray()
|
return KotlinPropertyShortNameIndex.getInstance().get(name, project, scope).asSequence()
|
||||||
|
.map { LightClassUtil.getLightClassBackingField(it) }
|
||||||
|
.filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAllFieldNames(): Array<String>
|
override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array<PsiField> {
|
||||||
= emptyArray()
|
return getFieldSequenceByName(name, scope).toList().toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAllFieldNames(): Array<String> {
|
||||||
|
return KotlinPropertyShortNameIndex.getInstance().getAllKeys(project).toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
override fun getAllFieldNames(set: HashSet<String>) {
|
override fun getAllFieldNames(set: HashSet<String>) {
|
||||||
|
set.addAll(allFieldNames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,18 +18,24 @@ package org.jetbrains.kotlin.idea.core
|
|||||||
|
|
||||||
import com.intellij.codeInsight.JavaProjectCodeInsightSettings
|
import com.intellij.codeInsight.JavaProjectCodeInsightSettings
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.PsiMember
|
import com.intellij.psi.PsiMember
|
||||||
import com.intellij.psi.PsiModifier
|
import com.intellij.psi.PsiModifier
|
||||||
|
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.search.PsiShortNamesCache
|
import com.intellij.psi.search.PsiShortNamesCache
|
||||||
import com.intellij.psi.stubs.StringStubIndexExtension
|
import com.intellij.psi.stubs.StringStubIndexExtension
|
||||||
import com.intellij.util.indexing.IdFilter
|
import com.intellij.util.indexing.IdFilter
|
||||||
|
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.*
|
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||||
import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension
|
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.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
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.search.usagesSearch.descriptor
|
||||||
import org.jetbrains.kotlin.idea.stubindex.*
|
import org.jetbrains.kotlin.idea.stubindex.*
|
||||||
import org.jetbrains.kotlin.idea.util.CallType
|
import org.jetbrains.kotlin.idea.util.CallType
|
||||||
@@ -59,6 +65,7 @@ class KotlinIndicesHelper(
|
|||||||
|
|
||||||
private val moduleDescriptor = resolutionFacade.moduleDescriptor
|
private val moduleDescriptor = resolutionFacade.moduleDescriptor
|
||||||
private val project = resolutionFacade.project
|
private val project = resolutionFacade.project
|
||||||
|
private val scopeWithoutKotlin = scope.excludeKotlinSources() as GlobalSearchScope
|
||||||
|
|
||||||
private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@ {
|
private val descriptorFilter: (DeclarationDescriptor) -> Boolean = filter@ {
|
||||||
if (it.isHiddenInResolution()) return@filter false
|
if (it.isHiddenInResolution()) return@filter false
|
||||||
@@ -202,9 +209,10 @@ class KotlinIndicesHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getJvmCallablesByName(name: String): Collection<CallableDescriptor> {
|
fun getJvmCallablesByName(name: String): Collection<CallableDescriptor> {
|
||||||
val javaDeclarations = PsiShortNamesCache.getInstance(project).getFieldsByName(name, scope).asSequence() +
|
val javaDeclarations = PsiShortNamesCache.getInstance(project).getFieldsByName(name, scopeWithoutKotlin).asSequence() +
|
||||||
PsiShortNamesCache.getInstance(project).getMethodsByName(name, scope).asSequence()
|
PsiShortNamesCache.getInstance(project).getMethodsByName(name, scopeWithoutKotlin).asSequence()
|
||||||
return javaDeclarations
|
return javaDeclarations
|
||||||
|
.filterNot { it is KtLightElement<*,*> }
|
||||||
.mapNotNull { (it as PsiMember).getJavaMemberDescriptor(resolutionFacade) as? CallableDescriptor }
|
.mapNotNull { (it as PsiMember).getJavaMemberDescriptor(resolutionFacade) as? CallableDescriptor }
|
||||||
.filter(descriptorFilter)
|
.filter(descriptorFilter)
|
||||||
.toSet()
|
.toSet()
|
||||||
@@ -298,11 +306,11 @@ class KotlinIndicesHelper(
|
|||||||
val shortNamesCache = PsiShortNamesCache.getInstance(project)
|
val shortNamesCache = PsiShortNamesCache.getInstance(project)
|
||||||
|
|
||||||
val allMethodNames = hashSetOf<String>()
|
val allMethodNames = hashSetOf<String>()
|
||||||
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) {
|
for (name in allMethodNames) {
|
||||||
ProgressManager.checkCanceled()
|
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 (!method.hasModifierProperty(PsiModifier.STATIC)) continue
|
||||||
if (filterOutPrivate && method.hasModifierProperty(PsiModifier.PRIVATE)) continue
|
if (filterOutPrivate && method.hasModifierProperty(PsiModifier.PRIVATE)) continue
|
||||||
if (method.containingClass?.parent !is PsiFile) continue // only top-level classes
|
if (method.containingClass?.parent !is PsiFile) continue // only top-level classes
|
||||||
@@ -321,11 +329,11 @@ class KotlinIndicesHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val allFieldNames = hashSetOf<String>()
|
val allFieldNames = hashSetOf<String>()
|
||||||
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) {
|
for (name in allFieldNames) {
|
||||||
ProgressManager.checkCanceled()
|
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 (!field.hasModifierProperty(PsiModifier.STATIC)) continue
|
||||||
if (filterOutPrivate && field.hasModifierProperty(PsiModifier.PRIVATE)) continue
|
if (filterOutPrivate && field.hasModifierProperty(PsiModifier.PRIVATE)) continue
|
||||||
val descriptor = field.getJavaFieldDescriptor() ?: continue
|
val descriptor = field.getJavaFieldDescriptor() ?: continue
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ import com.intellij.openapi.vfs.VirtualFile
|
|||||||
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.stubs.StubIndex
|
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.decompiler.builtIns.KotlinBuiltInFileType
|
||||||
import org.jetbrains.kotlin.idea.stubindex.*
|
import org.jetbrains.kotlin.idea.stubindex.*
|
||||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.containingClass
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class KotlinGotoClassContributor : GotoClassContributor {
|
class KotlinGotoClassContributor : GotoClassContributor {
|
||||||
@@ -78,8 +80,14 @@ class KotlinGotoSymbolContributor : ChooseByNameContributor {
|
|||||||
val noLibrarySourceScope = KotlinSourceFilterScope.projectSourceAndClassFiles(baseScope, project)
|
val noLibrarySourceScope = KotlinSourceFilterScope.projectSourceAndClassFiles(baseScope, project)
|
||||||
|
|
||||||
val result = ArrayList<NavigationItem>()
|
val result = ArrayList<NavigationItem>()
|
||||||
result += KotlinFunctionShortNameIndex.getInstance().get(name, project, noLibrarySourceScope)
|
result += KotlinFunctionShortNameIndex.getInstance().get(name, project, noLibrarySourceScope).filter {
|
||||||
result += KotlinPropertyShortNameIndex.getInstance().get(name, project, noLibrarySourceScope)
|
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 += KotlinClassShortNameIndex.getInstance().get(name, project, BuiltInClassesScope(noLibrarySourceScope))
|
||||||
result += KotlinTypeAliasShortNameIndex.getInstance().get(name, project, noLibrarySourceScope)
|
result += KotlinTypeAliasShortNameIndex.getInstance().get(name, project, noLibrarySourceScope)
|
||||||
|
|
||||||
|
|||||||
@@ -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 = ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
object B1 {
|
||||||
|
@JvmField
|
||||||
|
val foobar = ""
|
||||||
|
|
||||||
|
fun method1(){}
|
||||||
|
|
||||||
|
fun methodInBoth(){}
|
||||||
|
}
|
||||||
|
|
||||||
|
object B2 {
|
||||||
|
val barfoo = ""
|
||||||
|
|
||||||
|
fun method2(){}
|
||||||
|
|
||||||
|
fun methodInBoth(){}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class C1 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object O1 {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
@JvmField
|
||||||
|
var topLevelVar = ""
|
||||||
|
|
||||||
|
object B1 {
|
||||||
|
@JvmField
|
||||||
|
var objectVar = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
class C1 {
|
||||||
|
@JvmField
|
||||||
|
var classVar = ""
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
var companionVar = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
fun topLevelFunction(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
object B1 {
|
||||||
|
@JvmStatic
|
||||||
|
fun staticMethodOfObject() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonStaticMethodOfObject() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C1 {
|
||||||
|
fun methodOfClass() {
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun staticMethodOfCompanion() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonStaticMethodOfCompanion() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -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<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+43
@@ -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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vendored
+41
@@ -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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vendored
+41
@@ -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<caret>("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<caret>("foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vendored
+43
@@ -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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Vendored
+44
@@ -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<caret>("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<caret>("foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+39
@@ -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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+39
@@ -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<caret>("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<caret>("foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+41
@@ -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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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<caret>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+42
@@ -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<caret>("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<caret>("foobar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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<PsiMethod>)
|
||||||
|
= a.map { "${(it as KtLightMethod).clsDelegate.getKotlinFqName()} static=${it.hasModifierProperty(PsiModifier.STATIC)}" }.joinToString("\n")
|
||||||
|
|
||||||
|
fun accessorArrayDebugToString(a: Array<PsiMethod>)
|
||||||
|
= 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<PsiMethod>, 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<String, String> {
|
||||||
|
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<PsiMethod>, 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<PsiField>, 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<PsiField>)
|
||||||
|
= 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() + "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -167,6 +167,78 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
|||||||
doTestWithExtraFile(fileName);
|
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")
|
@TestMetadata("importTrait.before.Main.kt")
|
||||||
public void testImportTrait() throws Exception {
|
public void testImportTrait() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importTrait.before.Main.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/importTrait.before.Main.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user