From b51edf90040d0a5423917f4c2a53e5bc368b39a2 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Sat, 12 Sep 2015 20:52:18 +0300 Subject: [PATCH] Fixed completion for package, import directive and user type. --- .../kotlin/psi/psiUtil/jetPsiUtil.kt | 14 ++--- .../codeInsight/ReferenceVariantsHelper.kt | 60 ++++++++++++++++--- .../testData/basic/common/InEmptyPackage.kt | 3 + .../testData/basic/common/InPackage.kt | 5 ++ .../test/JSBasicCompletionTestGenerated.java | 12 ++++ .../test/JvmBasicCompletionTestGenerated.java | 12 ++++ 6 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/InEmptyPackage.kt create mode 100644 idea/idea-completion/testData/basic/common/InPackage.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt index 575a843e717..41db8ad8b59 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt @@ -91,7 +91,7 @@ public fun JetElement.getQualifiedElementSelector(): JetElement? { public fun JetSimpleNameExpression.getReceiverExpression(): JetExpression? { val parent = getParent() when { - parent is JetQualifiedExpression && !isImportDirectiveExpression() -> { + parent is JetQualifiedExpression -> { val receiverExpression = parent.getReceiverExpression() // Name expression can't be receiver for itself if (receiverExpression != this) { @@ -342,12 +342,12 @@ public fun JetModifierListOwner.isPrivate(): Boolean = hasModifier(JetTokens.PRI public fun JetSimpleNameExpression.isImportDirectiveExpression(): Boolean { val parent = getParent() - if (parent == null) { - return false - } - else { - return parent is JetImportDirective || parent.getParent() is JetImportDirective - } + return parent is JetImportDirective || parent?.getParent() is JetImportDirective +} + +public fun JetSimpleNameExpression.isPackageDirectiveExpression(): Boolean { + val parent = getParent() + return parent is JetPackageDirective || parent?.getParent() is JetPackageDirective } public fun JetExpression.isFunctionLiteralOutsideParentheses(): Boolean { diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index 72adf022d86..fe306ab818a 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -28,9 +28,13 @@ import org.jetbrains.kotlin.idea.util.ShadowedDeclarationsFilter import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression +import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression +import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager @@ -102,18 +106,20 @@ public class ReferenceVariantsHelper( explicitReceiverData: ExplicitReceiverData?, useRuntimeReceiverType: Boolean ): Collection { - val parent = expression.getParent() + if (expression.isImportDirectiveExpression()) { + return getVariantsForImportOrPackageDirective(explicitReceiverData, kindFilter, nameFilter) + } + if (expression.isPackageDirectiveExpression()) { + val packageKindFilter = kindFilter restrictedToKinds DescriptorKindFilter.PACKAGES_MASK + return getVariantsForImportOrPackageDirective(explicitReceiverData, packageKindFilter, nameFilter) + } + if (expression.getParent() is JetUserType) { + return getVariantsForUserType(explicitReceiverData, expression, kindFilter, nameFilter) + } + val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf() val containingDeclaration = resolutionScope.getContainingDeclaration() - if (parent is JetImportDirective || parent is JetPackageDirective) { - return resolutionScope.getDescriptorsFiltered(kindFilter.restrictedToKinds(DescriptorKindFilter.PACKAGES_MASK), nameFilter) - } - - if (parent is JetUserType) { - return resolutionScope.getDescriptorsFiltered(kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK), nameFilter) - } - val descriptors = LinkedHashSet() val dataFlowInfo = context.getDataFlowInfo(expression) @@ -163,6 +169,40 @@ public class ReferenceVariantsHelper( return descriptors } + private fun getVariantsForUserType( + explicitReceiverData: ExplicitReceiverData?, + expression: JetSimpleNameExpression, + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean + ): Collection { + val accurateKindFilter = kindFilter.restrictedToKinds(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) + if (explicitReceiverData != null) { + val qualifier = context[BindingContext.QUALIFIER, explicitReceiverData.expression] ?: return emptyList() + return qualifier.scope.getDescriptorsFiltered(accurateKindFilter, nameFilter) + } + else { + val lexicalScope = expression.getParentOfType(strict = true)?.let { + context[BindingContext.TYPE_RESOLUTION_SCOPE, it] + } ?: return emptyList() + return lexicalScope.getDescriptorsFiltered(accurateKindFilter, nameFilter) + } + } + + private fun getVariantsForImportOrPackageDirective( + explicitReceiverData: ExplicitReceiverData?, + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean + ): Collection { + if (explicitReceiverData != null) { + val qualifier = context[BindingContext.QUALIFIER, explicitReceiverData.expression] ?: return emptyList() + return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter) + } + else { + val rootPackage = resolutionFacade.moduleDescriptor.getPackage(FqName.ROOT) + return rootPackage.memberScope.getDescriptorsFiltered(kindFilter, nameFilter) + } + } + private fun MutableSet.processAll( implicitReceiverTypes: Collection, receiverTypes: Collection, @@ -304,6 +344,8 @@ public class ReferenceVariantsHelper( is JetUnaryExpression -> CallType.UNARY + is JetUserType -> CallType.NORMAL + else -> return null } return ExplicitReceiverData(receiverExpression, callType) diff --git a/idea/idea-completion/testData/basic/common/InEmptyPackage.kt b/idea/idea-completion/testData/basic/common/InEmptyPackage.kt new file mode 100644 index 00000000000..6699002848f --- /dev/null +++ b/idea/idea-completion/testData/basic/common/InEmptyPackage.kt @@ -0,0 +1,3 @@ +package + +// EXIST: java, kotlin diff --git a/idea/idea-completion/testData/basic/common/InPackage.kt b/idea/idea-completion/testData/basic/common/InPackage.kt new file mode 100644 index 00000000000..25ad9c71226 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/InPackage.kt @@ -0,0 +1,5 @@ +package java. + + +// EXIST: util, lang +// EXIST_JAVA_ONLY: awt \ No newline at end of file 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 ed6e8e38524..f16ea246cd8 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 @@ -253,6 +253,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("InEmptyPackage.kt") + public void testInEmptyPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InEmptyPackage.kt"); + doTest(fileName); + } + @TestMetadata("InExpressionNoPrefix.kt") public void testInExpressionNoPrefix() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InExpressionNoPrefix.kt"); @@ -355,6 +361,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("InPackage.kt") + public void testInPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InPackage.kt"); + doTest(fileName); + } + @TestMetadata("InParametersTypes.kt") public void testInParametersTypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InParametersTypes.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 d7e5f2b3b06..4e99d14750b 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 @@ -253,6 +253,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("InEmptyPackage.kt") + public void testInEmptyPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InEmptyPackage.kt"); + doTest(fileName); + } + @TestMetadata("InExpressionNoPrefix.kt") public void testInExpressionNoPrefix() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InExpressionNoPrefix.kt"); @@ -355,6 +361,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("InPackage.kt") + public void testInPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InPackage.kt"); + doTest(fileName); + } + @TestMetadata("InParametersTypes.kt") public void testInParametersTypes() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/InParametersTypes.kt");