Filtering out type parameters that are not visible at the completion point

This commit is contained in:
Valentin Kipyatkov
2015-06-23 13:02:54 +03:00
parent e894a04ce6
commit afa46f1c95
12 changed files with 154 additions and 20 deletions
@@ -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()
@@ -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 {
@@ -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())
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,11 @@
package ppp
class X<T1> {
fun <T2> f5(xxxValue1: T1, xxxValue2: T2){}
class Nested {
fun foo(xxx<caret>)
}
}
// NOTHING_ELSE
@@ -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
@@ -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");
@@ -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");