From e0fca9d2f6540957f502cc030f713d5d6eabbcb3 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Tue, 30 Mar 2021 14:48:38 +0300 Subject: [PATCH] FIR IDE: Add visibility checks to the completion Visibility checks currently do not work in some cases, for example: - public nested class of private class is seen globally - private_for_this does not work - some other cases I am not yet aware of If `FirVisibilityChecker.isVisible` fix those issues, they will be fixed automatically in the completion --- .../NoSecondPressCompletionInAutoPopup.kt | 1 + .../VisibilityClassMembersFromExternal.kt | 1 + .../common/visibility/VisibilityInSubclass.kt | 1 + ...OfClassMembersFromLocalClassConstructor.kt | 19 ++++ ...ilityOfClassMembersFromLocalClassMember.kt | 19 ++++ ...lityOfCompanionObjectMembersFromOutside.kt | 27 ++++++ ...ityOfCompanionObjectMembersFromSubclass.kt | 29 ++++++ .../basic/java/JavaSyntheticProperty.kt | 1 + .../NotImportedClass.dependency.kt | 13 +++ .../NotImportedClass/NotImportedClass.kt | 7 ++ ...NotImportedExtensionProperty.dependency.kt | 4 +- .../NotImportedExtensionProperty.kt | 6 +- .../NotImportedFunction.dependency.kt | 2 + .../NotImportedFunction.kt | 1 + ...dNestedClassFromPrivateClass.dependency.kt | 11 +++ .../NotImportedNestedClassFromPrivateClass.kt | 13 +++ .../TopLevelFunction.dependency.kt | 4 +- .../TopLevelFunction/TopLevelFunction.kt | 3 +- .../test/JSBasicCompletionTestGenerated.java | 20 ++++ .../test/JvmBasicCompletionTestGenerated.java | 20 ++++ ...tiFileJvmBasicCompletionTestGenerated.java | 10 ++ .../KotlinFirCompletionContributor.kt | 93 +++++++++++++------ ...hLevelJvmBasicCompletionTestGenerated.java | 20 ++++ ...tiFileJvmBasicCompletionTestGenerated.java | 10 ++ 24 files changed, 303 insertions(+), 32 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt create mode 100644 idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt create mode 100644 idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt create mode 100644 idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt create mode 100644 idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.dependency.kt create mode 100644 idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.kt create mode 100644 idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.dependency.kt create mode 100644 idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.kt diff --git a/idea/idea-completion/testData/basic/common/autoPopup/NoSecondPressCompletionInAutoPopup.kt b/idea/idea-completion/testData/basic/common/autoPopup/NoSecondPressCompletionInAutoPopup.kt index b4befb699a9..d8a394673b1 100644 --- a/idea/idea-completion/testData/basic/common/autoPopup/NoSecondPressCompletionInAutoPopup.kt +++ b/idea/idea-completion/testData/basic/common/autoPopup/NoSecondPressCompletionInAutoPopup.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON object O { private val zzzz = 0 } diff --git a/idea/idea-completion/testData/basic/common/visibility/VisibilityClassMembersFromExternal.kt b/idea/idea-completion/testData/basic/common/visibility/VisibilityClassMembersFromExternal.kt index 662f3d61895..7b48df0da1e 100644 --- a/idea/idea-completion/testData/basic/common/visibility/VisibilityClassMembersFromExternal.kt +++ b/idea/idea-completion/testData/basic/common/visibility/VisibilityClassMembersFromExternal.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class Some() { public val testPublic = 12 protected val testProtected = 12 diff --git a/idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclass.kt b/idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclass.kt index 302008b9955..f863ab841b2 100644 --- a/idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclass.kt +++ b/idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclass.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class Some() { public val testPublic = 12 protected val testProtected = 12 diff --git a/idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt new file mode 100644 index 00000000000..5738c4c6569 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt @@ -0,0 +1,19 @@ +// FIR_COMPARISON +package test + +open class Base { + public val testPublic = 12 + protected val testProtected = 12 + private val testPrivate = 12 + val testPackage = 12 + + fun baseClassMember() { + class Local { + init { + + } + } + } +} + +// EXIST: testPublic, testProtected, testPackage, testPrivate diff --git a/idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt new file mode 100644 index 00000000000..56bbfb9e2e8 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt @@ -0,0 +1,19 @@ +// FIR_COMPARISON +package test + +open class Base { + public val testPublic = 12 + protected val testProtected = 12 + private val testPrivate = 12 + val testPackage = 12 + + fun baseClassMember() { + class Local { + fun localClassMemeber() { + + } + } + } +} + +// EXIST: testPublic, testProtected, testPackage, testPrivate diff --git a/idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt new file mode 100644 index 00000000000..5e832164eb8 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt @@ -0,0 +1,27 @@ +// FIR_COMPARISON +package test + +open class BaseClass { + companion object { + val publicVal = 10 + fun publicFun() {} + + protected val protectedVal = 30 + protected fun protectedFun() {} + + private val privateVal = 30 + private fun privateFun() {} + } +} + +fun test() { + BaseClass. +} + +// EXIST: publicVal +// EXIST: publicFun + +// ABSENT: protectedVal +// ABSENT: protectedFun +// ABSENT: privateVal +// ABSENT: privateFun diff --git a/idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt new file mode 100644 index 00000000000..3dabd9841d4 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt @@ -0,0 +1,29 @@ +// FIR_COMPARISON +package test + +open class BaseClass { + companion object { + val publicVal = 10 + fun publicFun() {} + + protected val protectedVal = 30 + protected fun protectedFun() {} + + private val privateVal = 30 + private fun privateFun() {} + } +} + +class Subclass : BaseClass() { + fun test() { + BaseClass. + } +} + +// EXIST: publicVal +// EXIST: publicFun +// EXIST: protectedVal +// EXIST: protectedFun + +// ABSENT: privateVal +// ABSENT: privateFun diff --git a/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt b/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt index 38b9a181517..4f4bb3af5be 100644 --- a/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt +++ b/idea/idea-completion/testData/basic/java/JavaSyntheticProperty.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON fun foo(a: java.lang.Thread) { a.na } diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.dependency.kt b/idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.dependency.kt new file mode 100644 index 00000000000..ea2418aacc1 --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.dependency.kt @@ -0,0 +1,13 @@ +package dependency + +class PublicTopLevelClass { + class PublicNestedClass + protected class ProtectedNestedClass + private class PrivateNestedClass + + inner class PublicInnerClass + protected inner class ProtectedInnerClass + private inner class PrivateInnerClass +} + +private class PrivateTopLevelClass \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.kt b/idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.kt new file mode 100644 index 00000000000..bec461eb8eb --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/NotImportedClass/NotImportedClass.kt @@ -0,0 +1,7 @@ +// FIR_COMPARISON +package test + +fun usage(): P {} + +// EXIST: PublicTopLevelClass, PublicNestedClass, PublicInnerClass +// ABSENT: PrivateNestedClass, PrivateInnerClass, ProtectedNestedClass, ProtectedInnerClass, PrivateTopLevelClass \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.dependency.kt b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.dependency.kt index 21c09f7f633..1b23a45343c 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.dependency.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.dependency.kt @@ -3,4 +3,6 @@ package abc val String.helloProp1: Int get() = 1 val String.helloProp2: Int get() = 2 val Int.helloProp3: Int get() = 3 -val helloProp4: Int = 4 \ No newline at end of file +val helloProp4: Int = 4 + +private val String.helloPropPrivate get() = 1 \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.kt b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.kt index e0e7f2f7ef2..d0fed164e16 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedExtensionProperty/NotImportedExtensionProperty.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON package first fun firstFun() { @@ -5,8 +6,9 @@ fun firstFun() { a.hello } -// EXIST: { lookupString: "helloProp1", attributes: "bold" } -// EXIST: { lookupString: "helloProp2", attributes: "bold" } +// EXIST: helloProp1 +// EXIST: helloProp2 // ABSENT: helloProp3 // ABSENT: helloProp4 +// ABSENT: helloPropPrivate // NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.dependency.kt b/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.dependency.kt index 78598dde93c..7683dd5a4d6 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.dependency.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.dependency.kt @@ -6,3 +6,5 @@ fun globalFun2(): Int = 1 object Some { fun globalFun3(): Int = 3 } + +private fun globalFunPrivate() {} diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.kt b/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.kt index b78f1b2395a..e6460d2d7a8 100644 --- a/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.kt +++ b/idea/idea-completion/testData/basic/multifile/NotImportedFunction/NotImportedFunction.kt @@ -7,3 +7,4 @@ fun testFun() { // EXIST: globalFun1, globalFun2 // ABSENT: globalFun3 +// ABSENT: globalFunPrivate diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.dependency.kt b/idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.dependency.kt new file mode 100644 index 00000000000..bc3495664fa --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.dependency.kt @@ -0,0 +1,11 @@ +package dependency + +private class PrivateTopLevelClass { + class PublicNestedClass + protected class ProtectedNestedClass + private class PrivateNestedClass + + inner class PublicInnerClass + protected inner class ProtectedInnerClass + private inner class PrivateInnerClass +} \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.kt b/idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.kt new file mode 100644 index 00000000000..a169154d8cc --- /dev/null +++ b/idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/NotImportedNestedClassFromPrivateClass.kt @@ -0,0 +1,13 @@ +package test + +fun usage(): P {} + +// ABSENT: PrivateTopLevelClass + +// ABSENT: PublicNestedClass +// ABSENT: ProtectedNestedClass +// ABSENT: PrivateNestedClass + +// ABSENT: PublicInnerClass +// ABSENT: ProtectedInnerClass +// ABSENT: PrivateInnerClass diff --git a/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.dependency.kt b/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.dependency.kt index 0201ce312ee..d24b7b889de 100644 --- a/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.dependency.kt +++ b/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.dependency.kt @@ -1,4 +1,6 @@ package first fun secondFun() { -} \ No newline at end of file +} + +private fun secondFunPrivate() {} \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.kt b/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.kt index f790f23c0ed..4db9aa7da05 100644 --- a/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.kt +++ b/idea/idea-completion/testData/basic/multifile/TopLevelFunction/TopLevelFunction.kt @@ -5,4 +5,5 @@ fun firstFun() { s } -// EXIST: secondFun \ No newline at end of file +// EXIST: secondFun +// ABSENT: secondFunPrivate \ 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 92bee62d87a..3b99db7bbd7 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 @@ -2882,6 +2882,26 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclassForce.kt"); } + @TestMetadata("VisibilityOfClassMembersFromLocalClassConstructor.kt") + public void testVisibilityOfClassMembersFromLocalClassConstructor() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt"); + } + + @TestMetadata("VisibilityOfClassMembersFromLocalClassMember.kt") + public void testVisibilityOfClassMembersFromLocalClassMember() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt"); + } + + @TestMetadata("VisibilityOfCompanionObjectMembersFromOutside.kt") + public void testVisibilityOfCompanionObjectMembersFromOutside() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt"); + } + + @TestMetadata("VisibilityOfCompanionObjectMembersFromSubclass.kt") + public void testVisibilityOfCompanionObjectMembersFromSubclass() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt"); + } + @TestMetadata("VisibilityPrivateToThis.kt") public void testVisibilityPrivateToThis() throws Exception { runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityPrivateToThis.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 ff0b04bfbd1..bf05d90ea1b 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 @@ -2882,6 +2882,26 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclassForce.kt"); } + @TestMetadata("VisibilityOfClassMembersFromLocalClassConstructor.kt") + public void testVisibilityOfClassMembersFromLocalClassConstructor() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt"); + } + + @TestMetadata("VisibilityOfClassMembersFromLocalClassMember.kt") + public void testVisibilityOfClassMembersFromLocalClassMember() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt"); + } + + @TestMetadata("VisibilityOfCompanionObjectMembersFromOutside.kt") + public void testVisibilityOfCompanionObjectMembersFromOutside() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt"); + } + + @TestMetadata("VisibilityOfCompanionObjectMembersFromSubclass.kt") + public void testVisibilityOfCompanionObjectMembersFromSubclass() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt"); + } + @TestMetadata("VisibilityPrivateToThis.kt") public void testVisibilityPrivateToThis() throws Exception { runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityPrivateToThis.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java index deae3fa2998..64f7c095002 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java @@ -224,6 +224,11 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ runTest("idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/"); } + @TestMetadata("NotImportedClass") + public void testNotImportedClass() throws Exception { + runTest("idea/idea-completion/testData/basic/multifile/NotImportedClass/"); + } + @TestMetadata("NotImportedExtensionForImplicitReceiver") public void testNotImportedExtensionForImplicitReceiver() throws Exception { runTest("idea/idea-completion/testData/basic/multifile/NotImportedExtensionForImplicitReceiver/"); @@ -269,6 +274,11 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ runTest("idea/idea-completion/testData/basic/multifile/NotImportedJavaClass/"); } + @TestMetadata("NotImportedNestedClassFromPrivateClass") + public void testNotImportedNestedClassFromPrivateClass() throws Exception { + runTest("idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/"); + } + @TestMetadata("NotImportedObject") public void testNotImportedObject() throws Exception { runTest("idea/idea-completion/testData/basic/multifile/NotImportedObject/"); diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt index 10aedd3db57..1744c42bcf2 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt @@ -21,10 +21,9 @@ import org.jetbrains.kotlin.idea.frontend.api.analyseInFakeAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.scopes.KtCompositeScope import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter -import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol -import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol -import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.isExtension import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType import org.jetbrains.kotlin.idea.frontend.api.types.KtType @@ -86,6 +85,18 @@ private fun interface ExtensionApplicabilityChecker { fun isApplicable(symbol: KtCallableSymbol): Boolean } +private fun interface CompletionVisibilityChecker { + fun isVisible(symbol: KtSymbolWithVisibility): Boolean + + fun isVisible(symbol: KtCallableSymbol): Boolean { + return symbol !is KtSymbolWithVisibility || isVisible(symbol as KtSymbolWithVisibility) + } + + fun isVisible(symbol: KtClassifierSymbol): Boolean { + return symbol !is KtSymbolWithVisibility || isVisible(symbol as KtSymbolWithVisibility) + } +} + /** * Currently, this class is responsible for collecting all possible completion variants. * @@ -138,6 +149,7 @@ private class KotlinCommonCompletionProvider( val explicitReceiver = nameExpression.getReceiverExpression() analyseInFakeAnalysisSession(originalFile, nameExpression) { + val fileSymbol = originalFile.getFileSymbol() val expectedType = nameExpression.getExpectedType() val scopesContext = originalFile.getScopeContextForPosition(nameExpression) @@ -146,16 +158,24 @@ private class KotlinCommonCompletionProvider( it.checkExtensionIsSuitable(originalFile, nameExpression, explicitReceiver) } + val visibilityChecker = CompletionVisibilityChecker { + parameters.invocationCount > 1 || isVisible(it, fileSymbol, explicitReceiver, parameters.position) + } + when { - nameExpression.parent is KtUserType -> collectTypesCompletion(result, scopesContext.scopes, expectedType) - explicitReceiver != null -> collectDotCompletion( - result, - scopesContext.scopes, - explicitReceiver, - expectedType, - extensionChecker - ) - else -> collectDefaultCompletion(result, scopesContext, expectedType, extensionChecker) + nameExpression.parent is KtUserType -> collectTypesCompletion(result, scopesContext.scopes, expectedType, visibilityChecker) + explicitReceiver != null -> { + collectDotCompletion( + result, + scopesContext.scopes, + explicitReceiver, + expectedType, + extensionChecker, + visibilityChecker, + ) + } + + else -> collectDefaultCompletion(result, scopesContext, expectedType, extensionChecker, visibilityChecker) } } } @@ -164,12 +184,19 @@ private class KotlinCommonCompletionProvider( result: CompletionResultSet, implicitScopes: KtScope, expectedType: KtType?, + visibilityChecker: CompletionVisibilityChecker, ) { - val classesFromScopes = implicitScopes.getClassifierSymbols(scopeNameFilter) + val classesFromScopes = implicitScopes + .getClassifierSymbols(scopeNameFilter) + .filter { visibilityChecker.isVisible(it) } + classesFromScopes.forEach { addSymbolToCompletion(result, expectedType, it) } val kotlinClassesFromIndices = indexHelper.getKotlinClasses(scopeNameFilter, psiFilter = { it !is KtEnumEntry }) - kotlinClassesFromIndices.forEach { addSymbolToCompletion(result, expectedType, it.getSymbol()) } + kotlinClassesFromIndices.asSequence() + .map { it.getSymbol() as KtClassifierSymbol } + .filter { visibilityChecker.isVisible(it) } + .forEach { addSymbolToCompletion(result, expectedType, it) } } private fun KtAnalysisSession.collectDotCompletion( @@ -178,19 +205,19 @@ private class KotlinCommonCompletionProvider( explicitReceiver: KtExpression, expectedType: KtType?, extensionChecker: ExtensionApplicabilityChecker, + visibilityChecker: CompletionVisibilityChecker, ) { val typeOfPossibleReceiver = explicitReceiver.getKtType() val possibleReceiverScope = typeOfPossibleReceiver.getTypeScope() ?: return - val nonExtensionMembers = possibleReceiverScope.collectNonExtensions() - val extensionNonMembers = implicitScopes.collectSuitableExtensions(extensionChecker) + val nonExtensionMembers = possibleReceiverScope.collectNonExtensions(visibilityChecker) + val extensionNonMembers = implicitScopes.collectSuitableExtensions(extensionChecker, visibilityChecker) nonExtensionMembers.forEach { addSymbolToCompletion(result, expectedType, it) } extensionNonMembers.forEach { addSymbolToCompletion(result, expectedType, it) } - collectTopLevelExtensionsFromIndices(listOf(typeOfPossibleReceiver), extensionChecker) + collectTopLevelExtensionsFromIndices(listOf(typeOfPossibleReceiver), extensionChecker, visibilityChecker) .forEach { addSymbolToCompletion(result, expectedType, it) } - } private fun KtAnalysisSession.collectDefaultCompletion( @@ -198,11 +225,12 @@ private class KotlinCommonCompletionProvider( implicitScopesContext: KtScopeContext, expectedType: KtType?, extensionChecker: ExtensionApplicabilityChecker, + visibilityChecker: CompletionVisibilityChecker, ) { val (implicitScopes, implicitReceiversTypes) = implicitScopesContext - val availableNonExtensions = implicitScopes.collectNonExtensions() - val extensionsWhichCanBeCalled = implicitScopes.collectSuitableExtensions(extensionChecker) + val availableNonExtensions = implicitScopes.collectNonExtensions(visibilityChecker) + val extensionsWhichCanBeCalled = implicitScopes.collectSuitableExtensions(extensionChecker, visibilityChecker) availableNonExtensions.forEach { addSymbolToCompletion(result, expectedType, it) } extensionsWhichCanBeCalled.forEach { addSymbolToCompletion(result, expectedType, it) } @@ -210,33 +238,44 @@ private class KotlinCommonCompletionProvider( if (shouldCompleteTopLevelCallablesFromIndex) { val topLevelCallables = indexHelper.getTopLevelCallables(scopeNameFilter) topLevelCallables.asSequence() - .map { it.getSymbol() } + .map { it.getSymbol() as KtCallableSymbol } + .filter { visibilityChecker.isVisible(it) } .forEach { addSymbolToCompletion(result, expectedType, it) } } - collectTopLevelExtensionsFromIndices(implicitReceiversTypes, extensionChecker) + collectTopLevelExtensionsFromIndices(implicitReceiversTypes, extensionChecker, visibilityChecker) .forEach { addSymbolToCompletion(result, expectedType, it) } - collectTypesCompletion(result, implicitScopes, expectedType) + collectTypesCompletion(result, implicitScopes, expectedType, visibilityChecker) } private fun KtAnalysisSession.collectTopLevelExtensionsFromIndices( receiverTypes: List, extensionChecker: ExtensionApplicabilityChecker, + visibilityChecker: CompletionVisibilityChecker, ): Sequence { val implicitReceiverNames = findAllNamesOfTypes(receiverTypes) val topLevelExtensions = indexHelper.getTopLevelExtensions(scopeNameFilter, implicitReceiverNames) return topLevelExtensions.asSequence() .map { it.getSymbol() as KtCallableSymbol } + .filter { visibilityChecker.isVisible(it) } .filter { extensionChecker.isApplicable(it) } } - private fun KtScope.collectNonExtensions(): Sequence = - getCallableSymbols(scopeNameFilter).filterNot { it.isExtension } + private fun KtScope.collectNonExtensions(visibilityChecker: CompletionVisibilityChecker) = + getCallableSymbols(scopeNameFilter) + .filterNot { it.isExtension } + .filter { visibilityChecker.isVisible(it) } - private fun KtScope.collectSuitableExtensions(extensionChecker: ExtensionApplicabilityChecker): Sequence = - getCallableSymbols(scopeNameFilter).filter { it.isExtension && extensionChecker.isApplicable(it) } + private fun KtCompositeScope.collectSuitableExtensions( + hasSuitableExtensionReceiver: ExtensionApplicabilityChecker, + visibilityChecker: CompletionVisibilityChecker, + ): Sequence = + getCallableSymbols(scopeNameFilter) + .filter { it.isExtension } + .filter { visibilityChecker.isVisible(it) } + .filter { hasSuitableExtensionReceiver.isApplicable(it) } private fun KtAnalysisSession.findAllNamesOfTypes(implicitReceiversTypes: List) = implicitReceiversTypes.flatMapTo(hashSetOf()) { with(typeNamesProvider) { findAllNames(it) } } diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java index 611c20013d4..23cf21ee62b 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelJvmBasicCompletionTestGenerated.java @@ -2882,6 +2882,26 @@ public class HighLevelJvmBasicCompletionTestGenerated extends AbstractHighLevelJ runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityInSubclassForce.kt"); } + @TestMetadata("VisibilityOfClassMembersFromLocalClassConstructor.kt") + public void testVisibilityOfClassMembersFromLocalClassConstructor() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassConstructor.kt"); + } + + @TestMetadata("VisibilityOfClassMembersFromLocalClassMember.kt") + public void testVisibilityOfClassMembersFromLocalClassMember() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfClassMembersFromLocalClassMember.kt"); + } + + @TestMetadata("VisibilityOfCompanionObjectMembersFromOutside.kt") + public void testVisibilityOfCompanionObjectMembersFromOutside() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromOutside.kt"); + } + + @TestMetadata("VisibilityOfCompanionObjectMembersFromSubclass.kt") + public void testVisibilityOfCompanionObjectMembersFromSubclass() throws Exception { + runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityOfCompanionObjectMembersFromSubclass.kt"); + } + @TestMetadata("VisibilityPrivateToThis.kt") public void testVisibilityPrivateToThis() throws Exception { runTest("idea/idea-completion/testData/basic/common/visibility/VisibilityPrivateToThis.kt"); diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java index d3fda097a6c..92628e49d61 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java @@ -224,6 +224,11 @@ public class HighLevelMultiFileJvmBasicCompletionTestGenerated extends AbstractH runTest("idea/idea-completion/testData/basic/multifile/NoGenericFunDuplication/"); } + @TestMetadata("NotImportedClass") + public void testNotImportedClass() throws Exception { + runTest("idea/idea-completion/testData/basic/multifile/NotImportedClass/"); + } + @TestMetadata("NotImportedExtensionForImplicitReceiver") public void testNotImportedExtensionForImplicitReceiver() throws Exception { runTest("idea/idea-completion/testData/basic/multifile/NotImportedExtensionForImplicitReceiver/"); @@ -269,6 +274,11 @@ public class HighLevelMultiFileJvmBasicCompletionTestGenerated extends AbstractH runTest("idea/idea-completion/testData/basic/multifile/NotImportedJavaClass/"); } + @TestMetadata("NotImportedNestedClassFromPrivateClass") + public void testNotImportedNestedClassFromPrivateClass() throws Exception { + runTest("idea/idea-completion/testData/basic/multifile/NotImportedNestedClassFromPrivateClass/"); + } + @TestMetadata("NotImportedObject") public void testNotImportedObject() throws Exception { runTest("idea/idea-completion/testData/basic/multifile/NotImportedObject/");