From 2eb04db95a96f18f62d0791340031576368ae2c3 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 29 Jul 2015 16:21:55 +0300 Subject: [PATCH] Extension SAM-adapters shown in completion --- .../synthetic/SamAdapterFunctionsScope.kt | 11 +++++++++++ .../kotlin/resolve/AllUnderImportsScope.kt | 4 ++++ .../kotlin/resolve/lazy/LazyImportScope.kt | 11 +++++++++++ .../resolve/scopes/AbstractScopeAdapter.kt | 4 ++++ .../kotlin/resolve/scopes/ChainedScope.kt | 3 +++ .../kotlin/resolve/scopes/FilteringScope.kt | 2 ++ .../kotlin/resolve/scopes/JetScope.kt | 1 + .../kotlin/resolve/scopes/JetScopeImpl.kt | 1 + .../resolve/scopes/SubstitutingScope.kt | 6 +++++- .../jetbrains/kotlin/types/ErrorUtils.java | 16 ++++++++++++++++ .../codeInsight/ReferenceVariantsHelper.kt | 19 ++++++++++++++++--- .../idea/completion/LookupElementFactory.kt | 4 ++++ .../basic/common/SAMAdaptersStatic.kt | 6 ++++++ .../testData/basic/custom/SAMAdapters.kt | 6 ++++++ .../custom/SAMAdaptersSrc/JavaClass.java | 5 +++++ .../test/JSBasicCompletionTestGenerated.java | 6 ++++++ .../test/JvmBasicCompletionTestGenerated.java | 6 ++++++ ...vmWithLibBasicCompletionTestGenerated.java | 6 ++++++ 18 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/SAMAdaptersStatic.kt create mode 100644 idea/idea-completion/testData/basic/custom/SAMAdapters.kt create mode 100644 idea/idea-completion/testData/basic/custom/SAMAdaptersSrc/JavaClass.java diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt index 1a5292b0695..923cd63e1ec 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.load.java.typeEnhacement.enhanceSignature import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.DescriptorSubstitutor @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeSubstitution import org.jetbrains.kotlin.types.Variance import java.util.ArrayList +import java.util.LinkedHashSet interface SamAdapterExtensionFunctionDescriptor : FunctionDescriptor { val originalFunction: FunctionDescriptor @@ -73,6 +75,15 @@ class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by Jet } } + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection { + return receiverTypes.flatMapTo(LinkedHashSet()) { type -> + type.memberScope.getDescriptors(DescriptorKindFilter.FUNCTIONS) + .filterIsInstance() + .map { extensionForFunction(it.original) } + .filterNotNull() + } + } + private class MyFunctionDescriptor( override val originalFunction: FunctionDescriptor ) : SamAdapterExtensionFunctionDescriptor, SimpleFunctionDescriptorImpl( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt index 7215b54cdff..564f6c8d879 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AllUnderImportsScope.kt @@ -66,6 +66,10 @@ class AllUnderImportsScope : JetScope { return scopes.flatMap { it.getSyntheticExtensionProperties(receiverTypes) } } + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection { + return scopes.flatMap { it.getSyntheticExtensionFunctions(receiverTypes) } + } + override fun getPackage(name: Name): PackageViewDescriptor? = null // packages are not imported by all under imports override fun getLocalVariable(name: Name): VariableDescriptor? = null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt index 0bd22454a69..e68b581f04d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/LazyImportScope.kt @@ -279,6 +279,17 @@ class LazyImportScope( } } + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection { + // we do not perform any filtering by visibility here because all descriptors from both visible/invisible filter scopes are to be added anyway + if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf() + + return importResolver.storageManager.compute { + importResolver.indexedImports.imports.flatMapTo(LinkedHashSet()) { import -> + importResolver.getImportScope(import, LookupMode.EVERYTHING).getSyntheticExtensionFunctions(receiverTypes) + } + } + } + override fun getDeclarationsByLabel(labelName: Name): Collection = listOf() override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt index e3cc2eb6c4f..8933318cc18 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/AbstractScopeAdapter.kt @@ -59,6 +59,10 @@ public abstract class AbstractScopeAdapter : JetScope { return workerScope.getSyntheticExtensionProperties(receiverTypes) } + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection { + return workerScope.getSyntheticExtensionFunctions(receiverTypes) + } + override fun getLocalVariable(name: Name): VariableDescriptor? { return workerScope.getLocalVariable(name) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt index 25978a42d96..80d3d152bfb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/ChainedScope.kt @@ -73,6 +73,9 @@ public open class ChainedScope( override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = getFromAllScopes { it.getSyntheticExtensionProperties(receiverTypes) } + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection + = getFromAllScopes { it.getSyntheticExtensionFunctions(receiverTypes) } + override fun getImplicitReceiversHierarchy(): List { if (implicitReceiverHierarchy == null) { val result = ArrayList() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt index 7dfc19ae38f..b22c2fd0208 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/FilteringScope.kt @@ -44,6 +44,8 @@ public class FilteringScope(private val workerScope: JetScope, private val predi override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = workerScope.getSyntheticExtensionProperties(receiverTypes).filter(predicate) + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection = workerScope.getSyntheticExtensionFunctions(receiverTypes).filter(predicate) + override fun getLocalVariable(name: Name) = filterDescriptor(workerScope.getLocalVariable(name)) override fun getDescriptors(kindFilter: DescriptorKindFilter, diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt index 2a4f6913487..208540d2854 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScope.kt @@ -39,6 +39,7 @@ public interface JetScope { public fun getSyntheticExtensionFunctions(receiverTypes: Collection, name: Name): Collection public fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection + public fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection public fun getContainingDeclaration(): DeclarationDescriptor diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt index 4e3f1e68a9d..9496fe4bfea 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/JetScopeImpl.kt @@ -36,6 +36,7 @@ public abstract class JetScopeImpl : JetScope { override fun getSyntheticExtensionFunctions(receiverTypes: Collection, name: Name): Collection = emptyList() override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = emptyList() + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection = emptyList() override fun getDeclarationsByLabel(labelName: Name): Collection = emptyList() diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt index 333fe60d39e..ef33cf7f774 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/scopes/SubstitutingScope.kt @@ -76,7 +76,11 @@ public class SubstitutingScope(private val workerScope: JetScope, private val su override fun getSyntheticExtensionFunctions(receiverTypes: Collection, name: Name): Collection = substitute(workerScope.getSyntheticExtensionFunctions(receiverTypes, name)) - override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection = substitute(workerScope.getSyntheticExtensionProperties(receiverTypes)) + override fun getSyntheticExtensionProperties(receiverTypes: Collection): Collection + = substitute(workerScope.getSyntheticExtensionProperties(receiverTypes)) + + override fun getSyntheticExtensionFunctions(receiverTypes: Collection): Collection + = substitute(workerScope.getSyntheticExtensionFunctions(receiverTypes)) override fun getPackage(name: Name) = workerScope.getPackage(name) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java index 1fa03142d07..501e33d279f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/ErrorUtils.java @@ -115,6 +115,14 @@ public class ErrorUtils { return ERROR_PROPERTY_GROUP; } + @NotNull + @Override + public Collection getSyntheticExtensionFunctions( + @NotNull Collection receiverTypes + ) { + return Collections.singleton(createErrorFunction(this)); + } + @Override public VariableDescriptor getLocalVariable(@NotNull Name name) { return ERROR_PROPERTY; @@ -239,6 +247,14 @@ public class ErrorUtils { throw new IllegalStateException(); } + @NotNull + @Override + public Collection getSyntheticExtensionFunctions( + @NotNull Collection receiverTypes + ) { + throw new IllegalStateException(); + } + @NotNull @Override public DeclarationDescriptor getContainingDeclaration() { 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 9cc005276f6..31d981d21bb 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 @@ -42,7 +42,8 @@ import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.* +import java.util.HashSet +import java.util.LinkedHashSet public class ReferenceVariantsHelper( private val context: BindingContext, @@ -185,11 +186,23 @@ public class ReferenceVariantsHelper( } if (!kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) { - for (extension in resolutionScope.getSyntheticExtensionProperties(receiverTypes)) { - if (nameFilter(extension.getName()) && kindFilter.accepts(extension)) { + fun processExtension(extension: CallableDescriptor) { + if (nameFilter(extension.name) && kindFilter.accepts(extension)) { addAll(extension.substituteExtensionIfCallable(receiverValue, callType, context, dataFlowInfo, containingDeclaration)) } } + + if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) { + for (extension in resolutionScope.getSyntheticExtensionProperties(receiverTypes)) { + processExtension(extension) + } + } + + if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) { + for (extension in resolutionScope.getSyntheticExtensionFunctions(receiverTypes)) { + processExtension(extension) + } + } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index 70e0f9ad2df..20db3daa20f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils @@ -263,6 +264,9 @@ public class LookupElementFactory( element = element.appendTailText(" (from $from)", true) } + // no need to show them as extensions + original is SamAdapterExtensionFunctionDescriptor -> {} + extensionReceiver != null -> { val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type) element = element.appendTailText(" for $receiverPresentation", true) diff --git a/idea/idea-completion/testData/basic/common/SAMAdaptersStatic.kt b/idea/idea-completion/testData/basic/common/SAMAdaptersStatic.kt new file mode 100644 index 00000000000..813c3404165 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/SAMAdaptersStatic.kt @@ -0,0 +1,6 @@ +fun foo() { + javax.swing.SwingUtilities.invoke +} + +// EXIST_JAVA_ONLY: { lookupString: "invokeLater", itemText: "invokeLater", tailText: "(Runnable!)", typeText: "Unit" } +// EXIST_JAVA_ONLY: { lookupString: "invokeLater", itemText: "invokeLater", tailText: " {...} ((() -> Unit)!)", typeText: "Unit" } diff --git a/idea/idea-completion/testData/basic/custom/SAMAdapters.kt b/idea/idea-completion/testData/basic/custom/SAMAdapters.kt new file mode 100644 index 00000000000..06353153b8b --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SAMAdapters.kt @@ -0,0 +1,6 @@ +import lib.JavaClass + +fun test() = JavaClass(). + +// EXIST: { lookupString: "execute", itemText: "execute", tailText: "(Runnable!)", typeText: "Unit" } +// EXIST: { lookupString: "execute", itemText: "execute", tailText: " {...} ((() -> Unit)!)", typeText: "Unit" } diff --git a/idea/idea-completion/testData/basic/custom/SAMAdaptersSrc/JavaClass.java b/idea/idea-completion/testData/basic/custom/SAMAdaptersSrc/JavaClass.java new file mode 100644 index 00000000000..6ab4b6b03d6 --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SAMAdaptersSrc/JavaClass.java @@ -0,0 +1,5 @@ +package lib; + +public class JavaClass { + public void execute(Runnable runnable) {} +} 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 535fde8965e..1d71f74f904 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 @@ -769,6 +769,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } + @TestMetadata("SAMAdaptersStatic.kt") + public void testSAMAdaptersStatic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SAMAdaptersStatic.kt"); + doTest(fileName); + } + @TestMetadata("SafeCallAfterNullable.kt") public void testSafeCallAfterNullable() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SafeCallAfterNullable.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 42be488f5d7..63f02131177 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 @@ -769,6 +769,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } + @TestMetadata("SAMAdaptersStatic.kt") + public void testSAMAdaptersStatic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SAMAdaptersStatic.kt"); + doTest(fileName); + } + @TestMetadata("SafeCallAfterNullable.kt") public void testSafeCallAfterNullable() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/SafeCallAfterNullable.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmWithLibBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmWithLibBasicCompletionTestGenerated.java index faab28f02f1..d5848e98796 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmWithLibBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmWithLibBasicCompletionTestGenerated.java @@ -47,6 +47,12 @@ public class JvmWithLibBasicCompletionTestGenerated extends AbstractJvmWithLibBa doTest(fileName); } + @TestMetadata("SAMAdapters.kt") + public void testSAMAdapters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/custom/SAMAdapters.kt"); + doTest(fileName); + } + @TestMetadata("TopLevelNonImportedExtFun.kt") public void testTopLevelNonImportedExtFun() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/custom/TopLevelNonImportedExtFun.kt");