Experimental feature to show properties in completion after prefix with "get" or "set"
This commit is contained in:
@@ -42,14 +42,17 @@ import org.jetbrains.kotlin.idea.references.mainReference
|
|||||||
import org.jetbrains.kotlin.idea.util.CallType
|
import org.jetbrains.kotlin.idea.util.CallType
|
||||||
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
|
|
||||||
class CompletionSessionConfiguration(
|
class CompletionSessionConfiguration(
|
||||||
@@ -120,6 +123,18 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
|
|
||||||
protected val prefixMatcher: PrefixMatcher = CamelHumpMatcher(prefix)
|
protected val prefixMatcher: PrefixMatcher = CamelHumpMatcher(prefix)
|
||||||
|
|
||||||
|
protected val descriptorNameFilter: (Name) -> Boolean = run {
|
||||||
|
val nameFilter = prefixMatcher.asNameFilter()
|
||||||
|
val getOrSetPrefix = listOf("get", "set").firstOrNull { prefix.startsWith(it) }
|
||||||
|
if (getOrSetPrefix != null)
|
||||||
|
nameFilter or prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asNameFilter()
|
||||||
|
else
|
||||||
|
nameFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ((Name) -> Boolean).or(otherFilter: (Name) -> Boolean): (Name) -> Boolean
|
||||||
|
= { this(it) || otherFilter(it) }
|
||||||
|
|
||||||
protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it) }
|
protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it) }
|
||||||
|
|
||||||
protected val referenceVariantsHelper: ReferenceVariantsHelper = ReferenceVariantsHelper(bindingContext, moduleDescriptor, project, isVisibleFilter)
|
protected val referenceVariantsHelper: ReferenceVariantsHelper = ReferenceVariantsHelper(bindingContext, moduleDescriptor, project, isVisibleFilter)
|
||||||
@@ -207,7 +222,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
referenceVariantsHelper.getReferenceVariants(
|
referenceVariantsHelper.getReferenceVariants(
|
||||||
nameExpression!!,
|
nameExpression!!,
|
||||||
descriptorKindFilter!!,
|
descriptorKindFilter!!,
|
||||||
prefixMatcher.asNameFilter(),
|
descriptorNameFilter,
|
||||||
filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters
|
filterOutJavaGettersAndSetters = configuration.filterOutJavaGettersAndSetters
|
||||||
).excludeNonInitializedVariable(nameExpression)
|
).excludeNonInitializedVariable(nameExpression)
|
||||||
}
|
}
|
||||||
@@ -231,7 +246,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
|
|
||||||
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
||||||
val restrictedKindFilter = descriptorKindFilter!!.restrictedToKinds(DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK) // optimization
|
val restrictedKindFilter = descriptorKindFilter!!.restrictedToKinds(DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK) // optimization
|
||||||
val descriptors = referenceVariantsHelper.getReferenceVariants(nameExpression!!, restrictedKindFilter, prefixMatcher.asNameFilter(), useRuntimeReceiverType = true)
|
val descriptors = referenceVariantsHelper.getReferenceVariants(nameExpression!!, restrictedKindFilter, descriptorNameFilter, useRuntimeReceiverType = true)
|
||||||
return descriptors.filter { descriptor ->
|
return descriptors.filter { descriptor ->
|
||||||
referenceVariants.none { comparePossiblyOverridingDescriptors(project, it, descriptor) }
|
referenceVariants.none { comparePossiblyOverridingDescriptors(project, it, descriptor) }
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -86,7 +86,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
|||||||
|
|
||||||
private fun addLinkCompletions(declarationDescriptor: DeclarationDescriptor) {
|
private fun addLinkCompletions(declarationDescriptor: DeclarationDescriptor) {
|
||||||
val scope = getResolutionScope(resolutionFacade, declarationDescriptor)
|
val scope = getResolutionScope(resolutionFacade, declarationDescriptor)
|
||||||
scope.getDescriptors(nameFilter = prefixMatcher.asNameFilter()).forEach {
|
scope.getDescriptors(nameFilter = descriptorNameFilter).forEach {
|
||||||
val element = lookupElementFactory.createLookupElement(it, false)
|
val element = lookupElementFactory.createLookupElement(it, false)
|
||||||
collector.addElement(object: LookupElementDecorator<LookupElement>(element) {
|
collector.addElement(object: LookupElementDecorator<LookupElement>(element) {
|
||||||
override fun handleInsert(context: InsertionContext?) {
|
override fun handleInsert(context: InsertionContext?) {
|
||||||
|
|||||||
+16
-6
@@ -29,8 +29,7 @@ import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.*
|
import org.jetbrains.kotlin.idea.completion.handlers.*
|
||||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
@@ -40,7 +39,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import javax.swing.Icon
|
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.nullability
|
||||||
|
|
||||||
public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObject {
|
public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObject {
|
||||||
override val psiElement: PsiElement? get() = null
|
override val psiElement: PsiElement? get() = null
|
||||||
@@ -255,6 +255,7 @@ public class LookupElementFactory(
|
|||||||
|
|
||||||
if (descriptor is CallableDescriptor) {
|
if (descriptor is CallableDescriptor) {
|
||||||
val original = descriptor.original
|
val original = descriptor.original
|
||||||
|
val extensionReceiver = original.extensionReceiverParameter
|
||||||
when {
|
when {
|
||||||
original is SyntheticJavaPropertyDescriptor -> {
|
original is SyntheticJavaPropertyDescriptor -> {
|
||||||
var from = original.getMethod.getName().asString() + "()"
|
var from = original.getMethod.getName().asString() + "()"
|
||||||
@@ -262,9 +263,8 @@ public class LookupElementFactory(
|
|||||||
element = element.appendTailText(" (from $from)", true)
|
element = element.appendTailText(" (from $from)", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor.getExtensionReceiverParameter() != null -> {
|
extensionReceiver != null -> {
|
||||||
val originalReceiver = descriptor.getOriginal().getExtensionReceiverParameter()!!
|
val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type)
|
||||||
val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(originalReceiver.getType())
|
|
||||||
element = element.appendTailText(" for $receiverPresentation", true)
|
element = element.appendTailText(" for $receiverPresentation", true)
|
||||||
|
|
||||||
val container = descriptor.getContainingDeclaration()
|
val container = descriptor.getContainingDeclaration()
|
||||||
@@ -289,6 +289,16 @@ public class LookupElementFactory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (descriptor is PropertyDescriptor) {
|
||||||
|
val getterName = JvmAbi.getterName(name)
|
||||||
|
if (getterName != name) {
|
||||||
|
element = element.withLookupString(getterName)
|
||||||
|
}
|
||||||
|
if (descriptor.isVar) {
|
||||||
|
element = element.withLookupString(JvmAbi.setterName(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lookupObject.isDeprecated) {
|
if (lookupObject.isDeprecated) {
|
||||||
element = element.withStrikeoutness(true)
|
element = element.withStrikeoutness(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
class C : Thread() {
|
||||||
|
val property1: Int = 0
|
||||||
|
var property2: Int = 0
|
||||||
|
var xxx: Int = 0
|
||||||
|
|
||||||
|
fun getPPP() = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C) {
|
||||||
|
c.getP<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXIST: property1
|
||||||
|
// EXIST: property2
|
||||||
|
// EXIST: getPPP
|
||||||
|
// EXIST_JAVA_ONLY: priority
|
||||||
|
// ABSENT: getPriority
|
||||||
|
// ABSENT: xxx
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
class C {
|
||||||
|
val property1: Int = 0
|
||||||
|
var property2: Int = 0
|
||||||
|
var xxx: Int = 0
|
||||||
|
|
||||||
|
fun setPPP(){}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(c: C) {
|
||||||
|
c.setP<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
// ABSENT: property1
|
||||||
|
// EXIST: property2
|
||||||
|
// EXIST: setPPP
|
||||||
|
// ABSENT: xxx
|
||||||
-5
@@ -1,5 +0,0 @@
|
|||||||
fun foo(thread: Thread) {
|
|
||||||
thread.get<caret>
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXIST_JAVA_ONLY: getPriority
|
|
||||||
+12
-6
@@ -253,6 +253,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("GetPrefixForProperties.kt")
|
||||||
|
public void testGetPrefixForProperties() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("HigherOrderFunction1.kt")
|
@TestMetadata("HigherOrderFunction1.kt")
|
||||||
public void testHigherOrderFunction1() throws Exception {
|
public void testHigherOrderFunction1() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt");
|
||||||
@@ -769,6 +775,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SetPrefixForProperties.kt")
|
||||||
|
public void testSetPrefixForProperties() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ShortClassNamesInTypePosition.kt")
|
@TestMetadata("ShortClassNamesInTypePosition.kt")
|
||||||
public void testShortClassNamesInTypePosition() throws Exception {
|
public void testShortClassNamesInTypePosition() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ShortClassNamesInTypePosition.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ShortClassNamesInTypePosition.kt");
|
||||||
@@ -1227,12 +1239,6 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("ShowGetMethodWhenNothingElseMatch.kt")
|
|
||||||
public void testShowGetMethodWhenNothingElseMatch() throws Exception {
|
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("ShowGetSetOnSecondCompletion.kt")
|
@TestMetadata("ShowGetSetOnSecondCompletion.kt")
|
||||||
public void testShowGetSetOnSecondCompletion() throws Exception {
|
public void testShowGetSetOnSecondCompletion() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetSetOnSecondCompletion.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetSetOnSecondCompletion.kt");
|
||||||
|
|||||||
+12
-6
@@ -253,6 +253,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("GetPrefixForProperties.kt")
|
||||||
|
public void testGetPrefixForProperties() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/GetPrefixForProperties.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("HigherOrderFunction1.kt")
|
@TestMetadata("HigherOrderFunction1.kt")
|
||||||
public void testHigherOrderFunction1() throws Exception {
|
public void testHigherOrderFunction1() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt");
|
||||||
@@ -769,6 +775,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SetPrefixForProperties.kt")
|
||||||
|
public void testSetPrefixForProperties() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SetPrefixForProperties.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ShortClassNamesInTypePosition.kt")
|
@TestMetadata("ShortClassNamesInTypePosition.kt")
|
||||||
public void testShortClassNamesInTypePosition() throws Exception {
|
public void testShortClassNamesInTypePosition() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ShortClassNamesInTypePosition.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ShortClassNamesInTypePosition.kt");
|
||||||
@@ -1227,12 +1239,6 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("ShowGetMethodWhenNothingElseMatch.kt")
|
|
||||||
public void testShowGetMethodWhenNothingElseMatch() throws Exception {
|
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetMethodWhenNothingElseMatch.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("ShowGetSetOnSecondCompletion.kt")
|
@TestMetadata("ShowGetSetOnSecondCompletion.kt")
|
||||||
public void testShowGetSetOnSecondCompletion() throws Exception {
|
public void testShowGetSetOnSecondCompletion() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetSetOnSecondCompletion.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/extensions/ShowGetSetOnSecondCompletion.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user