diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 857b8c5ad90..ada259d8320 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -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(), 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 private val kotlinIdentifierPartPattern: ElementPattern @@ -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() } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index 11c32af07c7..e4b0d7583fe 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -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() diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt index aa4c2291db0..67f2955c8fb 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt @@ -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 { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt index 1dc6b705d51..df8f04a670a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt @@ -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() position.getContainingFile().forEachDescendantOfType( 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()) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt index c1665a6a9da..444fdcc5f65 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt @@ -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, diff --git a/idea/idea-completion/testData/basic/common/TypeParameterFromOuterClass.kt b/idea/idea-completion/testData/basic/common/TypeParameterFromOuterClass.kt new file mode 100644 index 00000000000..783765a897c --- /dev/null +++ b/idea/idea-completion/testData/basic/common/TypeParameterFromOuterClass.kt @@ -0,0 +1,7 @@ +class X { + class Nested { + val v: + } +} + +// ABSENT: T diff --git a/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileInaccessibleType2.kt b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileInaccessibleType2.kt new file mode 100644 index 00000000000..30e2ec17b2d --- /dev/null +++ b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileInaccessibleType2.kt @@ -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) { } + fun f4(nestedList: List) { } +} + +class C(val neste) + +// EXIST: { lookupString: "nested", itemText: "nested: X.PublicNested", tailText: " (ppp)" } +// EXIST: { lookupString: "nestedList", itemText: "nestedList: List", tailText: " (kotlin)" } +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter1.kt b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter1.kt new file mode 100644 index 00000000000..66a689535e7 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter1.kt @@ -0,0 +1,10 @@ +package ppp + +class X { + fun f(xxxValue1: T1, xxxValue2: T2, xxxValue3: (T2) -> Unit){} + + fun foo(xxx) +} + +// EXIST: { lookupString: "xxxValue1", itemText: "xxxValue1: T1", tailText: null } +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter2.kt b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter2.kt new file mode 100644 index 00000000000..3c09c535aaf --- /dev/null +++ b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter2.kt @@ -0,0 +1,11 @@ +package ppp + +class X { + fun f5(xxxValue1: T1, xxxValue2: T2){} + + class Nested { + fun foo(xxx) + } +} + +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter3.kt b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter3.kt new file mode 100644 index 00000000000..f774cc86809 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/parameterNameAndType/ParametersInFileTypeParameter3.kt @@ -0,0 +1,12 @@ +package ppp + +class X { + fun f5(xxxValue1: T1, xxxValue2: T2){} + + inner class Nested { + fun foo(xxx) + } +} + +// EXIST: { lookupString: "xxxValue1", itemText: "xxxValue1: T1", tailText: null } +// NOTHING_ELSE diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index aa659e3f549..1ddb34d33aa 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -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"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index d8aa48e59e4..cf2aebc8ef5 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -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");