Complete type instantiation items after "by"
This commit is contained in:
+4
-4
@@ -57,9 +57,9 @@ import java.util.*
|
|||||||
class BasicCompletionSession(
|
class BasicCompletionSession(
|
||||||
configuration: CompletionSessionConfiguration,
|
configuration: CompletionSessionConfiguration,
|
||||||
parameters: CompletionParameters,
|
parameters: CompletionParameters,
|
||||||
private val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||||
resultSet: CompletionResultSet
|
resultSet: CompletionResultSet
|
||||||
) : CompletionSession(configuration, parameters, resultSet) {
|
) : CompletionSession(configuration, parameters, toFromOriginalFileMapper, resultSet) {
|
||||||
|
|
||||||
private interface CompletionKind {
|
private interface CompletionKind {
|
||||||
val descriptorKindFilter: DescriptorKindFilter?
|
val descriptorKindFilter: DescriptorKindFilter?
|
||||||
@@ -197,11 +197,11 @@ class BasicCompletionSession(
|
|||||||
// getting root packages from scope is very slow so we do this in alternative way
|
// getting root packages from scope is very slow so we do this in alternative way
|
||||||
if (callTypeAndReceiver.receiver == null && callTypeAndReceiver.callType.descriptorKindFilter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) {
|
if (callTypeAndReceiver.receiver == null && callTypeAndReceiver.callType.descriptorKindFilter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) {
|
||||||
//TODO: move this code somewhere else?
|
//TODO: move this code somewhere else?
|
||||||
val packageNames = PackageIndexUtil.getSubPackageFqNames(FqName.ROOT, originalSearchScope, project, prefixMatcher.asNameFilter())
|
val packageNames = PackageIndexUtil.getSubPackageFqNames(FqName.ROOT, searchScope, project, prefixMatcher.asNameFilter())
|
||||||
.toMutableSet()
|
.toMutableSet()
|
||||||
|
|
||||||
if (!ProjectStructureUtil.isJsKotlinModule(parameters.originalFile as KtFile)) {
|
if (!ProjectStructureUtil.isJsKotlinModule(parameters.originalFile as KtFile)) {
|
||||||
JavaPsiFacade.getInstance(project).findPackage("")?.getSubPackages(originalSearchScope)?.forEach { psiPackage ->
|
JavaPsiFacade.getInstance(project).findPackage("")?.getSubPackages(searchScope)?.forEach { psiPackage ->
|
||||||
val name = psiPackage.name
|
val name = psiPackage.name
|
||||||
if (Name.isValidIdentifier(name!!)) {
|
if (Name.isValidIdentifier(name!!)) {
|
||||||
packageNames.add(FqName(name))
|
packageNames.add(FqName(name))
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ import com.intellij.codeInsight.completion.CompletionSorter
|
|||||||
import com.intellij.codeInsight.completion.CompletionUtil
|
import com.intellij.codeInsight.completion.CompletionUtil
|
||||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
|
||||||
import com.intellij.patterns.StandardPatterns
|
import com.intellij.patterns.StandardPatterns
|
||||||
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.*
|
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||||
@@ -70,6 +68,7 @@ fun CompletionSessionConfiguration(parameters: CompletionParameters) = Completio
|
|||||||
abstract class CompletionSession(
|
abstract class CompletionSession(
|
||||||
protected val configuration: CompletionSessionConfiguration,
|
protected val configuration: CompletionSessionConfiguration,
|
||||||
protected val parameters: CompletionParameters,
|
protected val parameters: CompletionParameters,
|
||||||
|
protected val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||||
resultSet: CompletionResultSet
|
resultSet: CompletionResultSet
|
||||||
) {
|
) {
|
||||||
protected val position = parameters.position
|
protected val position = parameters.position
|
||||||
@@ -148,16 +147,15 @@ abstract class CompletionSession(
|
|||||||
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter())
|
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter())
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val originalSearchScope: GlobalSearchScope = getResolveScope(parameters.getOriginalFile() as KtFile)
|
protected val searchScope: GlobalSearchScope = getResolveScope(parameters.originalFile as KtFile)
|
||||||
|
|
||||||
// we need to exclude the original file from scope because our resolve session is built with this file replaced by synthetic one
|
|
||||||
protected val searchScope: GlobalSearchScope = object : DelegatingGlobalSearchScope(originalSearchScope) {
|
|
||||||
override fun contains(file: VirtualFile) = super.contains(file) && file != parameters.originalFile.virtualFile
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun indicesHelper(mayIncludeInaccessible: Boolean): KotlinIndicesHelper {
|
protected fun indicesHelper(mayIncludeInaccessible: Boolean): KotlinIndicesHelper {
|
||||||
val filter = if (mayIncludeInaccessible) isVisibleFilter else isVisibleFilterCheckAlways
|
val filter = if (mayIncludeInaccessible) isVisibleFilter else isVisibleFilterCheckAlways
|
||||||
return KotlinIndicesHelper(resolutionFacade, searchScope, filter, filterOutPrivate = !mayIncludeInaccessible)
|
return KotlinIndicesHelper(resolutionFacade,
|
||||||
|
searchScope,
|
||||||
|
filter,
|
||||||
|
filterOutPrivate = !mayIncludeInaccessible,
|
||||||
|
declarationTranslator = { toFromOriginalFileMapper.toSyntheticFile(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
// excludes top-level extensions except for ones declared in the current file - those that are fetched from indices
|
// excludes top-level extensions except for ones declared in the current file - those that are fetched from indices
|
||||||
|
|||||||
+7
-4
@@ -59,12 +59,15 @@ class KDocCompletionContributor(): CompletionContributor() {
|
|||||||
|
|
||||||
object KDocNameCompletionProvider: CompletionProvider<CompletionParameters>() {
|
object KDocNameCompletionProvider: CompletionProvider<CompletionParameters>() {
|
||||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||||
KDocNameCompletionSession(parameters, result).complete()
|
KDocNameCompletionSession(parameters, ToFromOriginalFileMapper.create(parameters), result).complete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KDocNameCompletionSession(parameters: CompletionParameters,
|
class KDocNameCompletionSession(
|
||||||
resultSet: CompletionResultSet): CompletionSession(CompletionSessionConfiguration(parameters), parameters, resultSet) {
|
parameters: CompletionParameters,
|
||||||
|
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||||
|
resultSet: CompletionResultSet
|
||||||
|
): CompletionSession(CompletionSessionConfiguration(parameters), parameters, toFromOriginalFileMapper, resultSet) {
|
||||||
override val descriptorKindFilter: DescriptorKindFilter? get() = null
|
override val descriptorKindFilter: DescriptorKindFilter? get() = null
|
||||||
override val expectedInfos: Collection<ExpectedInfo> get() = emptyList()
|
override val expectedInfos: Collection<ExpectedInfo> get() = emptyList()
|
||||||
|
|
||||||
@@ -85,7 +88,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
|||||||
val section = position.getContainingSection()
|
val section = position.getContainingSection()
|
||||||
val documentedParameters = section.findTagsByName("param").map { it.getSubjectName() }.toSet()
|
val documentedParameters = section.findTagsByName("param").map { it.getSubjectName() }.toSet()
|
||||||
val descriptors = getParamDescriptors(declarationDescriptor)
|
val descriptors = getParamDescriptors(declarationDescriptor)
|
||||||
.filter { it.getName().asString() !in documentedParameters }
|
.filter { it.name.asString() !in documentedParameters }
|
||||||
|
|
||||||
descriptors.forEach {
|
descriptors.forEach {
|
||||||
collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true))
|
collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true))
|
||||||
|
|||||||
+3
-4
@@ -240,11 +240,10 @@ class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
|
|
||||||
private fun performCompletion(parameters: CompletionParameters, result: CompletionResultSet) {
|
private fun performCompletion(parameters: CompletionParameters, result: CompletionResultSet) {
|
||||||
val position = parameters.position
|
val position = parameters.position
|
||||||
val positionFile = position.containingFile as? KtFile ?: return
|
if (position.containingFile !is KtFile) return
|
||||||
val originalFile = parameters.originalFile as KtFile
|
if ((parameters.originalFile as KtFile).doNotComplete ?: false) return
|
||||||
if (originalFile.doNotComplete ?: false) return
|
|
||||||
|
|
||||||
val toFromOriginalFileMapper = ToFromOriginalFileMapper(originalFile, positionFile, parameters.offset)
|
val toFromOriginalFileMapper = ToFromOriginalFileMapper.create(parameters)
|
||||||
|
|
||||||
if (position.node.elementType == KtTokens.LONG_TEMPLATE_ENTRY_START) {
|
if (position.node.elementType == KtTokens.LONG_TEMPLATE_ENTRY_START) {
|
||||||
val expression = (position.parent as KtBlockStringTemplateEntry).expression
|
val expression = (position.parent as KtBlockStringTemplateEntry).expression
|
||||||
|
|||||||
+10
-1
@@ -16,16 +16,25 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.CompletionParameters
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
|
||||||
class ToFromOriginalFileMapper(
|
class ToFromOriginalFileMapper private constructor(
|
||||||
val originalFile: KtFile,
|
val originalFile: KtFile,
|
||||||
val syntheticFile: KtFile,
|
val syntheticFile: KtFile,
|
||||||
val completionOffset: Int
|
val completionOffset: Int
|
||||||
) {
|
) {
|
||||||
|
companion object {
|
||||||
|
fun create(parameters: CompletionParameters): ToFromOriginalFileMapper {
|
||||||
|
val originalFile = parameters.originalFile as KtFile
|
||||||
|
val syntheticFile = parameters.position.containingFile as KtFile
|
||||||
|
return ToFromOriginalFileMapper(originalFile, syntheticFile, parameters.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val syntheticLength: Int
|
private val syntheticLength: Int
|
||||||
private val originalLength: Int
|
private val originalLength: Int
|
||||||
private val tailLength: Int
|
private val tailLength: Int
|
||||||
|
|||||||
+2
-2
@@ -41,7 +41,7 @@ class SmartCompletionSession(
|
|||||||
parameters: CompletionParameters,
|
parameters: CompletionParameters,
|
||||||
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||||
resultSet: CompletionResultSet
|
resultSet: CompletionResultSet
|
||||||
) : CompletionSession(configuration, parameters, resultSet) {
|
) : CompletionSession(configuration, parameters, toFromOriginalFileMapper, resultSet) {
|
||||||
|
|
||||||
override val descriptorKindFilter: DescriptorKindFilter by lazy {
|
override val descriptorKindFilter: DescriptorKindFilter by lazy {
|
||||||
// we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes
|
// we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes
|
||||||
@@ -60,7 +60,7 @@ class SmartCompletionSession(
|
|||||||
private val smartCompletion by lazy(LazyThreadSafetyMode.NONE) {
|
private val smartCompletion by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
expression?.let {
|
expression?.let {
|
||||||
SmartCompletion(it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, indicesHelper(false),
|
SmartCompletion(it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, indicesHelper(false),
|
||||||
prefixMatcher, originalSearchScope, toFromOriginalFileMapper,
|
prefixMatcher, searchScope, toFromOriginalFileMapper,
|
||||||
callTypeAndReceiver, isJvmModule)
|
callTypeAndReceiver, isJvmModule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.idea.completion.*
|
|||||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||||
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
||||||
import org.jetbrains.kotlin.idea.core.Tail
|
import org.jetbrains.kotlin.idea.core.Tail
|
||||||
import org.jetbrains.kotlin.idea.core.fuzzyType
|
import org.jetbrains.kotlin.idea.core.multipleFuzzyTypes
|
||||||
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
|
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class TypeInstantiationItems(
|
class TypeInstantiationItems(
|
||||||
val resolutionFacade: ResolutionFacade,
|
val resolutionFacade: ResolutionFacade,
|
||||||
@@ -67,9 +68,14 @@ class TypeInstantiationItems(
|
|||||||
inheritanceSearchers: MutableCollection<InheritanceItemsSearcher>,
|
inheritanceSearchers: MutableCollection<InheritanceItemsSearcher>,
|
||||||
expectedInfos: Collection<ExpectedInfo>
|
expectedInfos: Collection<ExpectedInfo>
|
||||||
) {
|
) {
|
||||||
val expectedInfosGrouped: Map<FuzzyType?, List<ExpectedInfo>> = expectedInfos.groupBy { it.fuzzyType?.makeNotNullable() }
|
val expectedInfosGrouped = LinkedHashMap<FuzzyType, MutableList<ExpectedInfo>>()
|
||||||
|
for (expectedInfo in expectedInfos) {
|
||||||
|
for (fuzzyType in expectedInfo.multipleFuzzyTypes) {
|
||||||
|
expectedInfosGrouped.getOrPut(fuzzyType.makeNotNullable()) { ArrayList() }.add(expectedInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for ((type, infos) in expectedInfosGrouped) {
|
for ((type, infos) in expectedInfosGrouped) {
|
||||||
if (type == null) continue
|
|
||||||
val tail = mergeTails(infos.map { it.tail })
|
val tail = mergeTails(infos.map { it.tail })
|
||||||
addTo(items, inheritanceSearchers, type, tail)
|
addTo(items, inheritanceSearchers, type, tail)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -1,15 +1,16 @@
|
|||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
class Property<TOwner, TValue>
|
class Property<TOwner, TValue>(owner: TOwner, value: TValue)
|
||||||
|
|
||||||
operator fun <TValue, TOwner> Property<TOwner, TValue>.getValue(thisRef: TOwner, property: KProperty<*>): TValue {
|
operator fun <TValue, TOwner> Property<TOwner, TValue>.getValue(thisRef: TOwner, property: KProperty<*>): TValue {
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun<TOwner, TValue> createProperty(): Property<TOwner, TValue> = Property()
|
fun<TOwner, TValue> createProperty(owner: TOwner, value: TValue): Property<TOwner, TValue> = Property(owner, value)
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
val v by create<caret>
|
val v by <caret>
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXIST: { itemText: "createProperty", typeText: "Property<C, TValue>" }
|
// EXIST: { itemText: "createProperty", typeText: "Property<C, TValue>" }
|
||||||
|
// EXIST: Property
|
||||||
|
|||||||
+2
-1
@@ -9,7 +9,8 @@ operator fun <TValue, TOwner> Property<TOwner, TValue>.getValue(thisRef: TOwner,
|
|||||||
fun<TOwner, TValue> createProperty(): Property<TOwner, TValue> = Property()
|
fun<TOwner, TValue> createProperty(): Property<TOwner, TValue> = Property()
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
val v: Int by create<caret>
|
val v: Int by <caret>
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXIST: { itemText: "createProperty", typeText: "Property<C, Int>" }
|
// EXIST: { itemText: "createProperty", typeText: "Property<C, Int>" }
|
||||||
|
// EXIST: Property
|
||||||
|
|||||||
+2
-1
@@ -13,7 +13,8 @@ operator fun <TValue3, TOwner3> Property<TOwner3, TValue3>.setValue(thisRef: TOw
|
|||||||
fun<TOwner4, TValue4> createProperty(): Property<TOwner4, TValue4> = Property()
|
fun<TOwner4, TValue4> createProperty(): Property<TOwner4, TValue4> = Property()
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
var v by create<caret>
|
var v by <caret>
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXIST: { itemText: "createProperty", typeText: "Property<C, TValue4>" }
|
// EXIST: { itemText: "createProperty", typeText: "Property<C, TValue4>" }
|
||||||
|
// EXIST: Property
|
||||||
|
|||||||
+2
-1
@@ -13,7 +13,8 @@ operator fun <TValue3, TOwner3> Property<TOwner3, TValue3>.setValue(thisRef: TOw
|
|||||||
fun<TOwner4, TValue4> createProperty(): Property<TOwner4, TValue4> = Property()
|
fun<TOwner4, TValue4> createProperty(): Property<TOwner4, TValue4> = Property()
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
var v: Int by create<caret>
|
var v: Int by <caret>
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXIST: { itemText: "createProperty", typeText: "Property<C, Int>" }
|
// EXIST: { itemText: "createProperty", typeText: "Property<C, Int>" }
|
||||||
|
// EXIST: Property
|
||||||
|
|||||||
@@ -30,10 +30,17 @@ class C
|
|||||||
val C.property by <caret>
|
val C.property by <caret>
|
||||||
|
|
||||||
// EXIST: lazy
|
// EXIST: lazy
|
||||||
|
|
||||||
// EXIST: createX1
|
// EXIST: createX1
|
||||||
// ABSENT: createX2
|
// ABSENT: createX2
|
||||||
// EXIST: createX3
|
// EXIST: createX3
|
||||||
// EXIST: createY1
|
// EXIST: createY1
|
||||||
// ABSENT: createY2
|
// ABSENT: createY2
|
||||||
// EXIST: createY3
|
// EXIST: createY3
|
||||||
/*TODO: add constructors*/
|
|
||||||
|
// EXIST: X1
|
||||||
|
// ABSENT: X2
|
||||||
|
// EXIST: X3
|
||||||
|
// EXIST: Y1
|
||||||
|
// ABSENT: Y2
|
||||||
|
// EXIST: Y3
|
||||||
|
|||||||
@@ -35,8 +35,15 @@ class C
|
|||||||
var C.property by <caret>
|
var C.property by <caret>
|
||||||
|
|
||||||
// ABSENT: lazy
|
// ABSENT: lazy
|
||||||
|
|
||||||
// EXIST: createX1
|
// EXIST: createX1
|
||||||
// ABSENT: createX2
|
// ABSENT: createX2
|
||||||
// ABSENT: createX3
|
// ABSENT: createX3
|
||||||
// EXIST: createX4
|
// EXIST: createX4
|
||||||
// ABSENT: createX5
|
// ABSENT: createX5
|
||||||
|
|
||||||
|
// EXIST: X1
|
||||||
|
// ABSENT: X2
|
||||||
|
// ABSENT: X3
|
||||||
|
// EXIST: X4
|
||||||
|
// ABSENT: X5
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class X3 {
|
|||||||
|
|
||||||
class Y1
|
class Y1
|
||||||
class Y2
|
class Y2
|
||||||
class Y3
|
abstract class Y3
|
||||||
|
|
||||||
operator fun Y1.getValue(thisRef: C, property: KProperty<*>): String = ""
|
operator fun Y1.getValue(thisRef: C, property: KProperty<*>): String = ""
|
||||||
operator fun Y2.getValue(thisRef: String, property: KProperty<*>): String = ""
|
operator fun Y2.getValue(thisRef: String, property: KProperty<*>): String = ""
|
||||||
@@ -36,4 +36,9 @@ class C {
|
|||||||
// EXIST: createY1
|
// EXIST: createY1
|
||||||
// ABSENT: createY2
|
// ABSENT: createY2
|
||||||
// EXIST: createY3
|
// EXIST: createY3
|
||||||
/*TODO: add constructors*/
|
// EXIST: X1
|
||||||
|
// ABSENT: X2
|
||||||
|
// EXIST: X3
|
||||||
|
// EXIST: Y1
|
||||||
|
// ABSENT: Y2
|
||||||
|
// ABSENT: Y3
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ class X5 {
|
|||||||
operator fun setValue(thisRef: C, property: KProperty<*>, value: String) {}
|
operator fun setValue(thisRef: C, property: KProperty<*>, value: String) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Y1
|
||||||
|
class Y2
|
||||||
|
|
||||||
|
operator fun Y1.getValue(thisRef: C, property: KProperty<*>): String = ""
|
||||||
|
operator fun Y1.setValue(thisRef: C, property: KProperty<*>, value: String) {}
|
||||||
|
operator fun Y2.getValue(thisRef: C, property: KProperty<*>): String = ""
|
||||||
|
|
||||||
fun createX1() = X1()
|
fun createX1() = X1()
|
||||||
fun createX2() = X2()
|
fun createX2() = X2()
|
||||||
fun createX3() = X3()
|
fun createX3() = X3()
|
||||||
@@ -40,3 +47,10 @@ class C {
|
|||||||
// ABSENT: createX3
|
// ABSENT: createX3
|
||||||
// EXIST: createX4
|
// EXIST: createX4
|
||||||
// ABSENT: createX5
|
// ABSENT: createX5
|
||||||
|
// EXIST: X1
|
||||||
|
// ABSENT: X2
|
||||||
|
// ABSENT: X3
|
||||||
|
// EXIST: X4
|
||||||
|
// ABSENT: X5
|
||||||
|
// EXIST: Y1
|
||||||
|
// ABSENT: Y2
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.resolve.ideService
|
import org.jetbrains.kotlin.idea.resolve.ideService
|
||||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||||
|
import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
|
||||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -63,6 +64,12 @@ data class ItemOptions(val starPrefix: Boolean) {
|
|||||||
interface ByTypeFilter {
|
interface ByTypeFilter {
|
||||||
fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor?
|
fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor?
|
||||||
|
|
||||||
|
val fuzzyType: FuzzyType?
|
||||||
|
get() = null
|
||||||
|
|
||||||
|
val multipleFuzzyTypes: Collection<FuzzyType>
|
||||||
|
get() = fuzzyType.singletonOrEmptyList()
|
||||||
|
|
||||||
object All : ByTypeFilter {
|
object All : ByTypeFilter {
|
||||||
override fun matchingSubstitutor(descriptorType: FuzzyType) = TypeSubstitutor.EMPTY
|
override fun matchingSubstitutor(descriptorType: FuzzyType) = TypeSubstitutor.EMPTY
|
||||||
}
|
}
|
||||||
@@ -72,7 +79,7 @@ interface ByTypeFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ByExpectedTypeFilter(val fuzzyType: FuzzyType) : ByTypeFilter {
|
class ByExpectedTypeFilter(override val fuzzyType: FuzzyType) : ByTypeFilter {
|
||||||
override fun matchingSubstitutor(descriptorType: FuzzyType) = descriptorType.checkIsSubtypeOf(fuzzyType)
|
override fun matchingSubstitutor(descriptorType: FuzzyType) = descriptorType.checkIsSubtypeOf(fuzzyType)
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is ByExpectedTypeFilter && fuzzyType == other.fuzzyType
|
override fun equals(other: Any?) = other is ByExpectedTypeFilter && fuzzyType == other.fuzzyType
|
||||||
@@ -118,7 +125,10 @@ class ExpectedInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val ExpectedInfo.fuzzyType: FuzzyType?
|
val ExpectedInfo.fuzzyType: FuzzyType?
|
||||||
get() = (this.filter as? ByExpectedTypeFilter)?.fuzzyType
|
get() = filter.fuzzyType
|
||||||
|
|
||||||
|
val ExpectedInfo.multipleFuzzyTypes: Collection<FuzzyType>
|
||||||
|
get() = filter.multipleFuzzyTypes
|
||||||
|
|
||||||
sealed class ArgumentPositionData(val function: FunctionDescriptor, val callType: Call.CallType) : ExpectedInfo.AdditionalData {
|
sealed class ArgumentPositionData(val function: FunctionDescriptor, val callType: Call.CallType) : ExpectedInfo.AdditionalData {
|
||||||
class Positional(
|
class Positional(
|
||||||
@@ -632,6 +642,25 @@ class ExpectedInfos(
|
|||||||
TypeSubstitutor.createChainedSubstitutor(setOperatorSubstitutor.substitution,
|
TypeSubstitutor.createChainedSubstitutor(setOperatorSubstitutor.substitution,
|
||||||
setParamTypeSubstitutor.substitution).substitution)
|
setParamTypeSubstitutor.substitution).substitution)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val multipleFuzzyTypes: Collection<FuzzyType> by lazy {
|
||||||
|
val result = ArrayList<FuzzyType>()
|
||||||
|
|
||||||
|
for (classDescriptor in typesWithGetDetector.classesWithMemberOperators) {
|
||||||
|
val type = classDescriptor.defaultType
|
||||||
|
val typeParameters = classDescriptor.declaredTypeParameters
|
||||||
|
val substitutor = matchingSubstitutor(FuzzyType(type, typeParameters)) ?: continue
|
||||||
|
result.add(FuzzyType(substitutor.substitute(type, Variance.INVARIANT)!!, typeParameters))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (extensionOperator in typesWithGetDetector.extensionOperators) {
|
||||||
|
val receiverType = extensionOperator.fuzzyExtensionReceiverType()!!
|
||||||
|
val substitutor = matchingSubstitutor(receiverType) ?: continue
|
||||||
|
result.add(FuzzyType(substitutor.substitute(receiverType.type, Variance.INVARIANT)!!, receiverType.freeParameters))
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return listOf(ExpectedInfo(byTypeFilter, null, null))
|
return listOf(ExpectedInfo(byTypeFilter, null, null))
|
||||||
//TODO: special items for "Delegates...."
|
//TODO: special items for "Delegates...."
|
||||||
|
|||||||
@@ -42,10 +42,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.SamAdapterDescriptor
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
||||||
@@ -59,6 +56,7 @@ class KotlinIndicesHelper(
|
|||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
private val scope: GlobalSearchScope,
|
private val scope: GlobalSearchScope,
|
||||||
visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||||
|
private val declarationTranslator: (KtDeclaration) -> KtDeclaration? = { it },
|
||||||
applyExcludeSettings: Boolean = true,
|
applyExcludeSettings: Boolean = true,
|
||||||
private val filterOutPrivate: Boolean = true
|
private val filterOutPrivate: Boolean = true
|
||||||
) {
|
) {
|
||||||
@@ -94,7 +92,16 @@ class KotlinIndicesHelper(
|
|||||||
.filter { it.parent is KtFile && it.receiverTypeReference != null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
|
.filter { it.parent is KtFile && it.receiverTypeReference != null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
|
||||||
.flatMap { it.resolveToDescriptorsWithHack() }
|
.flatMap { it.resolveToDescriptorsWithHack() }
|
||||||
.filterIsInstance<FunctionDescriptor>()
|
.filterIsInstance<FunctionDescriptor>()
|
||||||
.filter { descriptorFilter(it) }
|
.filter { descriptorFilter(it) && it.extensionReceiverParameter != null }
|
||||||
|
.distinct()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMemberOperatorsByName(name: String): Collection<FunctionDescriptor> {
|
||||||
|
return KotlinFunctionShortNameIndex.getInstance().get(name, project, scope)
|
||||||
|
.filter { it.parent is KtClassBody && it.receiverTypeReference == null && it.hasModifier(KtTokens.OPERATOR_KEYWORD) }
|
||||||
|
.flatMap { it.resolveToDescriptorsWithHack() }
|
||||||
|
.filterIsInstance<FunctionDescriptor>()
|
||||||
|
.filter { descriptorFilter(it) && it.extensionReceiverParameter == null }
|
||||||
.distinct()
|
.distinct()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +323,8 @@ class KotlinIndicesHelper(
|
|||||||
return resolutionFacade.resolveImportReference(moduleDescriptor, fqName!!).filterIsInstance<CallableDescriptor>()
|
return resolutionFacade.resolveImportReference(moduleDescriptor, fqName!!).filterIsInstance<CallableDescriptor>()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (resolutionFacade.resolveToDescriptor(this) as? CallableDescriptor).singletonOrEmptyList()
|
val translatedDeclaration = declarationTranslator(this) ?: return emptyList()
|
||||||
|
return (resolutionFacade.resolveToDescriptor(translatedDeclaration) as? CallableDescriptor).singletonOrEmptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.core
|
package org.jetbrains.kotlin.idea.core
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||||
@@ -41,19 +42,32 @@ abstract class TypesWithOperatorDetector(
|
|||||||
|
|
||||||
private val cache = HashMap<FuzzyType, Pair<FunctionDescriptor, TypeSubstitutor>?>()
|
private val cache = HashMap<FuzzyType, Pair<FunctionDescriptor, TypeSubstitutor>?>()
|
||||||
|
|
||||||
private val extensionOperators: Collection<FunctionDescriptor> by lazy {
|
val extensionOperators: Collection<FunctionDescriptor> by lazy {
|
||||||
val result = ArrayList<FunctionDescriptor>()
|
val result = ArrayList<FunctionDescriptor>()
|
||||||
collectExtensionOperators(scope.collectFunctions(name, NoLookupLocation.FROM_IDE), result)
|
|
||||||
indicesHelper?.getTopLevelExtensionOperatorsByName(name.asString())?.let { collectExtensionOperators(it, result) }
|
val extensionsFromScope = scope
|
||||||
|
.collectFunctions(name, NoLookupLocation.FROM_IDE)
|
||||||
|
.filter { it.extensionReceiverParameter != null }
|
||||||
|
result.addSuitableOperators(extensionsFromScope)
|
||||||
|
|
||||||
|
indicesHelper?.getTopLevelExtensionOperatorsByName(name.asString())?.let { result.addSuitableOperators(it) }
|
||||||
|
|
||||||
result.distinctBy { it.original }
|
result.distinctBy { it.original }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectExtensionOperators(functions: Collection<FunctionDescriptor>, result: MutableCollection<FunctionDescriptor>) {
|
val classesWithMemberOperators: Collection<ClassDescriptor> by lazy {
|
||||||
|
if (indicesHelper == null) return@lazy emptyList<ClassDescriptor>()
|
||||||
|
val operators = ArrayList<FunctionDescriptor>().addSuitableOperators(indicesHelper.getMemberOperatorsByName(name.asString()))
|
||||||
|
operators.map { it.containingDeclaration as ClassDescriptor }.distinct()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableCollection<FunctionDescriptor>.addSuitableOperators(functions: Collection<FunctionDescriptor>): MutableCollection<FunctionDescriptor> {
|
||||||
for (function in functions) {
|
for (function in functions) {
|
||||||
if (function.extensionReceiverParameter == null || !function.isValidOperator()) continue
|
if (!function.isValidOperator()) continue
|
||||||
val substitutor = checkIsSuitableByType(function, function.typeParameters) ?: continue
|
val substitutor = checkIsSuitableByType(function, function.typeParameters) ?: continue
|
||||||
result.add(function.substitute(substitutor))
|
add(function.substitute(substitutor))
|
||||||
}
|
}
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findOperator(type: FuzzyType): Pair<FunctionDescriptor, TypeSubstitutor>? {
|
fun findOperator(type: FuzzyType): Pair<FunctionDescriptor, TypeSubstitutor>? {
|
||||||
|
|||||||
Reference in New Issue
Block a user