Filtering out type parameters that are not visible at the completion point
This commit is contained in:
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.idea.completion.smart.LambdaItems
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion
|
||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||
import org.jetbrains.kotlin.idea.core.comparePossiblyOverridingDescriptors
|
||||
import org.jetbrains.kotlin.idea.core.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
@@ -49,6 +50,7 @@ import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindEx
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastUtils
|
||||
@@ -99,7 +101,7 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
||||
}
|
||||
|
||||
protected val bindingContext: BindingContext = resolutionFacade.analyze(position.parentsWithSelf.firstIsInstance<JetElement>(), BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||
protected val inDescriptor: DeclarationDescriptor? = expression?.let { bindingContext.get(BindingContext.RESOLUTION_SCOPE, it)?.getContainingDeclaration() }
|
||||
protected val inDescriptor: DeclarationDescriptor = position.getResolutionScope(bindingContext, resolutionFacade).getContainingDeclaration()
|
||||
|
||||
private val kotlinIdentifierStartPattern: ElementPattern<Char>
|
||||
private val kotlinIdentifierPartPattern: ElementPattern<Char>
|
||||
@@ -169,7 +171,9 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
||||
get() = KotlinIndicesHelper(project, resolutionFacade, searchScope, moduleDescriptor, isVisibleFilter)
|
||||
|
||||
protected fun isVisibleDescriptor(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (descriptor is DeclarationDescriptorWithVisibility && inDescriptor != null) {
|
||||
if (descriptor is TypeParameterDescriptor && !isTypeParameterVisible(descriptor)) return false
|
||||
|
||||
if (descriptor is DeclarationDescriptorWithVisibility) {
|
||||
val visible = descriptor.isVisible(inDescriptor, bindingContext, reference?.expression)
|
||||
if (visible) return true
|
||||
if (!configuration.completeNonAccessibleDeclarations) return false
|
||||
@@ -179,6 +183,17 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isTypeParameterVisible(typeParameter: TypeParameterDescriptor): Boolean {
|
||||
val owner = typeParameter.getContainingDeclaration()
|
||||
var parent: DeclarationDescriptor? = inDescriptor
|
||||
while (parent != null) {
|
||||
if (parent == owner) return true
|
||||
if (parent is ClassDescriptor && !parent.isInner()) return false
|
||||
parent = parent.getContainingDeclaration()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun flushToResultSet() {
|
||||
collector.flushToResultSet()
|
||||
}
|
||||
|
||||
@@ -310,10 +310,9 @@ fun breakOrContinueExpressionItems(position: JetElement, breakOrContinue: String
|
||||
|
||||
fun LookupElementFactory.createBackingFieldLookupElement(
|
||||
property: PropertyDescriptor,
|
||||
inDescriptor: DeclarationDescriptor?,
|
||||
inDescriptor: DeclarationDescriptor,
|
||||
resolutionFacade: ResolutionFacade
|
||||
): LookupElement? {
|
||||
if (inDescriptor == null) return null // no backing field accessible
|
||||
val insideAccessor = inDescriptor is PropertyAccessorDescriptor && inDescriptor.getCorrespondingProperty() == property
|
||||
if (!insideAccessor) {
|
||||
val container = property.getContainingDeclaration()
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ class LookupElementsCollector(
|
||||
resultSet: CompletionResultSet,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
private val inDescriptor: DeclarationDescriptor?,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val context: LookupElementsCollector.Context
|
||||
) {
|
||||
public enum class Context {
|
||||
|
||||
+15
-14
@@ -16,18 +16,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionInitializationContext
|
||||
import com.intellij.codeInsight.completion.CompletionParameters
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
||||
import com.intellij.codeInsight.lookup.*
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||
import com.intellij.psi.codeStyle.NameUtil
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
@@ -37,17 +34,18 @@ import org.jetbrains.kotlin.idea.core.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.EmptyValidator
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetParameter
|
||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import java.util.*
|
||||
import java.util.HashSet
|
||||
import java.util.LinkedHashMap
|
||||
|
||||
class ParameterNameAndTypeCompletion(
|
||||
private val collector: LookupElementsCollector,
|
||||
@@ -109,12 +107,14 @@ class ParameterNameAndTypeCompletion(
|
||||
val lookupElementToCount = LinkedHashMap<LookupElement, Int>()
|
||||
position.getContainingFile().forEachDescendantOfType<JetParameter>(
|
||||
canGoInside = { it !is JetExpression || it is JetDeclaration } // we analyze parameters inside bodies to not resolve too much
|
||||
) { declaration ->
|
||||
val name = declaration.getName()
|
||||
) { parameter ->
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
val name = parameter.getName()
|
||||
if (name != null && parametersInCurrentFilePrefixMatcher.prefixMatches(name)) {
|
||||
val parameter = resolutionFacade.analyze(declaration)[BindingContext.VALUE_PARAMETER, declaration]
|
||||
if (parameter != null) {
|
||||
val parameterType = parameter.getType()
|
||||
val descriptor = resolutionFacade.analyze(parameter)[BindingContext.VALUE_PARAMETER, parameter]
|
||||
if (descriptor != null) {
|
||||
val parameterType = descriptor.getType()
|
||||
if (parameterType.isVisible(visibilityFilter)) {
|
||||
val lookupElement = MyLookupElement.create("", name, ArbitraryType(parameterType), lookupElementFactory)
|
||||
val count = lookupElementToCount[lookupElement] ?: 0
|
||||
@@ -139,6 +139,7 @@ class ParameterNameAndTypeCompletion(
|
||||
}
|
||||
|
||||
private fun addSuggestions(className: String, userPrefix: String, prefixMatcher: PrefixMatcher, type: Type) {
|
||||
ProgressManager.checkCanceled()
|
||||
if (suggestionsByTypesAdded.contains(type)) return // don't add suggestions for the same with longer user prefix
|
||||
|
||||
val nameSuggestions = JetNameSuggester.getCamelNames(className, EmptyValidator, userPrefix.isEmpty())
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ class SmartCompletion(
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val bindingContext: BindingContext,
|
||||
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
val inDescriptor: DeclarationDescriptor?,
|
||||
val inDescriptor: DeclarationDescriptor,
|
||||
val prefixMatcher: PrefixMatcher,
|
||||
val inheritorSearchScope: GlobalSearchScope,
|
||||
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class X<T> {
|
||||
class Nested {
|
||||
val v: <caret>
|
||||
}
|
||||
}
|
||||
|
||||
// ABSENT: T
|
||||
idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileInaccessibleType2.kt
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
package ppp
|
||||
|
||||
import java.io.*
|
||||
|
||||
class X {
|
||||
public class PublicNested
|
||||
private class PrivateNested
|
||||
|
||||
fun f1(nested: PublicNested) { }
|
||||
fun f2(nested: PrivateNested) { }
|
||||
fun f3(nestedList: List<PublicNested>) { }
|
||||
fun f4(nestedList: List<PrivateNested>) { }
|
||||
}
|
||||
|
||||
class C(val neste<caret>)
|
||||
|
||||
// EXIST: { lookupString: "nested", itemText: "nested: X.PublicNested", tailText: " (ppp)" }
|
||||
// EXIST: { lookupString: "nestedList", itemText: "nestedList: List<X.PublicNested>", tailText: " (kotlin)" }
|
||||
// NOTHING_ELSE
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
package ppp
|
||||
|
||||
class X<T1> {
|
||||
fun <T2> f(xxxValue1: T1, xxxValue2: T2, xxxValue3: (T2) -> Unit){}
|
||||
|
||||
fun foo(xxx<caret>)
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "xxxValue1", itemText: "xxxValue1: T1", tailText: null }
|
||||
// NOTHING_ELSE
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package ppp
|
||||
|
||||
class X<T1> {
|
||||
fun <T2> f5(xxxValue1: T1, xxxValue2: T2){}
|
||||
|
||||
class Nested {
|
||||
fun foo(xxx<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTHING_ELSE
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
package ppp
|
||||
|
||||
class X<T1> {
|
||||
fun <T2> f5(xxxValue1: T1, xxxValue2: T2){}
|
||||
|
||||
inner class Nested {
|
||||
fun foo(xxx<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "xxxValue1", itemText: "xxxValue1: T1", tailText: null }
|
||||
// NOTHING_ELSE
|
||||
+30
@@ -1027,6 +1027,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeParameterFromOuterClass.kt")
|
||||
public void testTypeParameterFromOuterClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeParameterFromOuterClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("VariableClassName.kt")
|
||||
public void testVariableClassName() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/VariableClassName.kt");
|
||||
@@ -1488,6 +1494,30 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileInaccessibleType2.kt")
|
||||
public void testParametersInFileInaccessibleType2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileInaccessibleType2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileTypeParameter1.kt")
|
||||
public void testParametersInFileTypeParameter1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileTypeParameter2.kt")
|
||||
public void testParametersInFileTypeParameter2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileTypeParameter3.kt")
|
||||
public void testParametersInFileTypeParameter3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/Simple.kt");
|
||||
|
||||
+30
@@ -1027,6 +1027,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeParameterFromOuterClass.kt")
|
||||
public void testTypeParameterFromOuterClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeParameterFromOuterClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("VariableClassName.kt")
|
||||
public void testVariableClassName() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/VariableClassName.kt");
|
||||
@@ -1488,6 +1494,30 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileInaccessibleType2.kt")
|
||||
public void testParametersInFileInaccessibleType2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileInaccessibleType2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileTypeParameter1.kt")
|
||||
public void testParametersInFileTypeParameter1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileTypeParameter2.kt")
|
||||
public void testParametersInFileTypeParameter2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParametersInFileTypeParameter3.kt")
|
||||
public void testParametersInFileTypeParameter3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/Simple.kt");
|
||||
|
||||
Reference in New Issue
Block a user