From b6cf39981fe66bc114b87a152eaedf500b1a1900 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 13 Aug 2015 21:10:26 +0300 Subject: [PATCH] SAM-adapters are sorted as non-extensions in completion and with correct boldness + no parameter names when from compiled --- .../kotlin/codegen/SamCodegenUtil.java | 2 +- .../synthetic/SamAdapterFunctionsScope.kt | 134 +++++++++++++----- .../idea/completion/LookupElementFactory.kt | 8 +- .../testData/basic/custom/SAMAdapters.kt | 6 - .../custom/SAMAdaptersSrc/JavaClass.java | 5 - .../testData/basic/custom/SamAdapter.kt | 8 ++ .../basic/custom/SamAdapterAndGenerics.kt | 8 ++ .../JavaInterface.java | 5 + .../custom/SamAdapterAndGenericsSrc/Task.java | 5 + .../basic/custom/SamAdapterSrc/JavaClass.java | 5 + ...vmWithLibBasicCompletionTestGenerated.java | 12 +- 11 files changed, 144 insertions(+), 54 deletions(-) delete mode 100644 idea/idea-completion/testData/basic/custom/SAMAdapters.kt delete mode 100644 idea/idea-completion/testData/basic/custom/SAMAdaptersSrc/JavaClass.java create mode 100644 idea/idea-completion/testData/basic/custom/SamAdapter.kt create mode 100644 idea/idea-completion/testData/basic/custom/SamAdapterAndGenerics.kt create mode 100644 idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/JavaInterface.java create mode 100644 idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/Task.java create mode 100644 idea/idea-completion/testData/basic/custom/SamAdapterSrc/JavaClass.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamCodegenUtil.java index e7f8e76787a..adae76db700 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamCodegenUtil.java @@ -32,7 +32,7 @@ public class SamCodegenUtil { } if (original instanceof SamAdapterExtensionFunctionDescriptor) { - return ((SamAdapterExtensionFunctionDescriptor) original).getOriginalFunction(); + return ((SamAdapterExtensionFunctionDescriptor) original).getSourceFunction(); } if (original.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { 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 5510bdb141e..a444fa5cb97 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/synthetic/SamAdapterFunctionsScope.kt @@ -29,15 +29,14 @@ 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 -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.TypeSubstitution -import org.jetbrains.kotlin.types.Variance +import org.jetbrains.kotlin.types.* import java.util.ArrayList +import java.util.HashMap import java.util.LinkedHashSet +import kotlin.properties.Delegates interface SamAdapterExtensionFunctionDescriptor : FunctionDescriptor { - val originalFunction: FunctionDescriptor + val sourceFunction: FunctionDescriptor } class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by JetScope.Empty { @@ -52,7 +51,7 @@ class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by Jet if (function.returnType == null) return null //TODO: it's a temporary hack while original returns a function with platform types val enhancedFunction = function.enhanceSignature() - return MyFunctionDescriptor(enhancedFunction) + return MyFunctionDescriptor.create(enhancedFunction) } override fun getSyntheticExtensionFunctions(receiverTypes: Collection, name: Name, location: LookupLocation): Collection { @@ -85,38 +84,101 @@ class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by Jet } private class MyFunctionDescriptor( - override val originalFunction: FunctionDescriptor - ) : SamAdapterExtensionFunctionDescriptor, SimpleFunctionDescriptorImpl( - DescriptorUtils.getContainingModule(originalFunction), - null, - Annotations.EMPTY, //TODO - originalFunction.name, - CallableMemberDescriptor.Kind.SYNTHESIZED, - originalFunction.source - ) { - init { - val typeParamsSum = (originalFunction.typeParameters).toArrayList() - val ownerClass = originalFunction.containingDeclaration as ClassDescriptor - //TODO: should we go up parents for getters/setters too? - for (parent in ownerClass.parentsWithSelf) { - if (parent !is ClassDescriptor) break - typeParamsSum += parent.typeConstructor.parameters + containingDeclaration: DeclarationDescriptor, + original: SimpleFunctionDescriptor?, + annotations: Annotations, + name: Name, + kind: CallableMemberDescriptor.Kind, + source: SourceElement + ) : SamAdapterExtensionFunctionDescriptor, SimpleFunctionDescriptorImpl(containingDeclaration, original, annotations, name, kind, source) { + + override var sourceFunction: FunctionDescriptor by Delegates.notNull() + private set + + private var toSourceFunctionTypeParameters: Map? = null + + companion object { + fun create(sourceFunction: FunctionDescriptor): MyFunctionDescriptor { + val descriptor = MyFunctionDescriptor(DescriptorUtils.getContainingModule(sourceFunction), + null, + Annotations.EMPTY, //TODO + sourceFunction.name, + CallableMemberDescriptor.Kind.SYNTHESIZED, + sourceFunction.source) + descriptor.sourceFunction = sourceFunction + + val sourceTypeParams = (sourceFunction.typeParameters).toArrayList() + val ownerClass = sourceFunction.containingDeclaration as ClassDescriptor + //TODO: should we go up parents for getters/setters too? + //TODO: non-inner classes + for (parent in ownerClass.parentsWithSelf) { + if (parent !is ClassDescriptor) break + sourceTypeParams += parent.typeConstructor.parameters + } + //TODO: duplicated parameter names + + val typeParameters = ArrayList(sourceTypeParams.size()) + val typeSubstitutor = DescriptorSubstitutor.substituteTypeParameters(sourceTypeParams, TypeSubstitution.EMPTY, descriptor, typeParameters) + + descriptor.toSourceFunctionTypeParameters = typeParameters.zip(sourceTypeParams).toMap() + + val returnType = typeSubstitutor.safeSubstitute(sourceFunction.returnType!!, Variance.INVARIANT) + val receiverType = typeSubstitutor.safeSubstitute(ownerClass.defaultType, Variance.INVARIANT) + val valueParameters = SingleAbstractMethodUtils.createValueParametersForSamAdapter(sourceFunction, descriptor, typeSubstitutor) + + val visibility = syntheticExtensionVisibility(sourceFunction) + + descriptor.initialize(receiverType, null, typeParameters, valueParameters, returnType, Modality.FINAL, visibility) + + return descriptor } - //TODO: duplicated parameter names - - val typeParameters = ArrayList(typeParamsSum.size()) - val typeSubstitutor = DescriptorSubstitutor.substituteTypeParameters(typeParamsSum, TypeSubstitution.EMPTY, this, typeParameters) - - val returnType = typeSubstitutor.safeSubstitute(originalFunction.returnType!!, Variance.INVARIANT) - val receiverType = typeSubstitutor.safeSubstitute(ownerClass.defaultType, Variance.INVARIANT) - val valueParameters = SingleAbstractMethodUtils.createValueParametersForSamAdapter(originalFunction, this, typeSubstitutor) - - val visibility = syntheticExtensionVisibility(originalFunction) - - initialize(receiverType, null, typeParameters, valueParameters, returnType, Modality.FINAL, visibility) } - override fun hasStableParameterNames() = originalFunction.hasStableParameterNames() - override fun hasSynthesizedParameterNames() = originalFunction.hasSynthesizedParameterNames() + override fun hasStableParameterNames() = sourceFunction.hasStableParameterNames() + override fun hasSynthesizedParameterNames() = sourceFunction.hasSynthesizedParameterNames() + + override fun createSubstitutedCopy(newOwner: DeclarationDescriptor, original: FunctionDescriptor?, kind: CallableMemberDescriptor.Kind): MyFunctionDescriptor { + return MyFunctionDescriptor(containingDeclaration, original as SimpleFunctionDescriptor?, annotations, name, kind, source).apply { + sourceFunction = this@MyFunctionDescriptor.sourceFunction + } + } + + override fun doSubstitute( + originalSubstitutor: TypeSubstitutor, + newOwner: DeclarationDescriptor, + newModality: Modality, + newVisibility: Visibility, + original: FunctionDescriptor?, + copyOverrides: Boolean, + kind: CallableMemberDescriptor.Kind, + newValueParameterDescriptors: MutableList, + newExtensionReceiverParameterType: JetType?, + newReturnType: JetType + ): FunctionDescriptor? { + val descriptor = super.doSubstitute( + originalSubstitutor, newOwner, newModality, newVisibility, original, + copyOverrides, kind, newValueParameterDescriptors, newExtensionReceiverParameterType, newReturnType) + as MyFunctionDescriptor? ?: return null + + if (original == null) { + throw UnsupportedOperationException("doSubstitute with no original should not be called for synthetic extension") + } + + original as MyFunctionDescriptor + assert(original.original == original, "original in doSubstitute should have no other original") + + val substitutionMap = HashMap() + for (typeParameter in original.typeParameters) { + val typeProjection = originalSubstitutor.substitution[typeParameter.defaultType] ?: continue + val sourceTypeParameter = original.toSourceFunctionTypeParameters!![typeParameter]!! + substitutionMap[sourceTypeParameter.typeConstructor] = typeProjection + + } + + val sourceFunctionSubstitutor = TypeSubstitutor.create(substitutionMap) + descriptor.sourceFunction = original.sourceFunction.substitute(sourceFunctionSubstitutor)!! + + return descriptor + } } } 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 2a6097897a8..48e767e5f92 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 @@ -255,8 +255,7 @@ public class LookupElementFactory( } if (descriptor is CallableDescriptor) { - val original = descriptor.original - val extensionReceiver = original.extensionReceiverParameter + val extensionReceiver = descriptor.original.extensionReceiverParameter when { descriptor is SyntheticJavaPropertyDescriptor -> { var from = descriptor.getMethod.getName().asString() + "()" @@ -265,7 +264,7 @@ public class LookupElementFactory( } // no need to show them as extensions - original is SamAdapterExtensionFunctionDescriptor -> {} + descriptor is SamAdapterExtensionFunctionDescriptor -> {} extensionReceiver != null -> { val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type) @@ -336,6 +335,9 @@ public class LookupElementFactory( if (descriptor is SyntheticJavaPropertyDescriptor) { return callableWeight(descriptor.getMethod) } + if (descriptor is SamAdapterExtensionFunctionDescriptor) { + return callableWeight(descriptor.sourceFunction) + } val receiverParameter = descriptor.extensionReceiverParameter ?: descriptor.dispatchReceiverParameter if (receiverParameter != null) { diff --git a/idea/idea-completion/testData/basic/custom/SAMAdapters.kt b/idea/idea-completion/testData/basic/custom/SAMAdapters.kt deleted file mode 100644 index 06353153b8b..00000000000 --- a/idea/idea-completion/testData/basic/custom/SAMAdapters.kt +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 6ab4b6b03d6..00000000000 --- a/idea/idea-completion/testData/basic/custom/SAMAdaptersSrc/JavaClass.java +++ /dev/null @@ -1,5 +0,0 @@ -package lib; - -public class JavaClass { - public void execute(Runnable runnable) {} -} diff --git a/idea/idea-completion/testData/basic/custom/SamAdapter.kt b/idea/idea-completion/testData/basic/custom/SamAdapter.kt new file mode 100644 index 00000000000..42f8f11b652 --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SamAdapter.kt @@ -0,0 +1,8 @@ +import lib.JavaClass + +class KotlinClass : JavaClass() + +fun test() = KotlinClass(). + +// EXIST: { lookupString: "execute", itemText: "execute", tailText: "(Runnable!, Int)", typeText: "Unit", attributes: "" } +// EXIST: { lookupString: "execute", itemText: "execute", tailText: "((() -> Unit)!, Int)", typeText: "Unit", attributes: "" } diff --git a/idea/idea-completion/testData/basic/custom/SamAdapterAndGenerics.kt b/idea/idea-completion/testData/basic/custom/SamAdapterAndGenerics.kt new file mode 100644 index 00000000000..3877c0656cf --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SamAdapterAndGenerics.kt @@ -0,0 +1,8 @@ +import lib.*; + +fun foo(j: JavaInterface) { + j. +} + +// EXIST: { lookupString: "execute", itemText: "execute", tailText: "(Task!, K!)", typeText: "String!", attributes: "bold" } +// EXIST: { lookupString: "execute", itemText: "execute", tailText: "(((String!) -> Unit)!, K!)", typeText: "String!", attributes: "bold" } diff --git a/idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/JavaInterface.java b/idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/JavaInterface.java new file mode 100644 index 00000000000..00968f1fa63 --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/JavaInterface.java @@ -0,0 +1,5 @@ +package lib; + +public interface JavaInterface { + T execute(Task task, K k); +} \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/Task.java b/idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/Task.java new file mode 100644 index 00000000000..0a4bbf6cc25 --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SamAdapterAndGenericsSrc/Task.java @@ -0,0 +1,5 @@ +package lib; + +public interface Task { + void run(T t); +} diff --git a/idea/idea-completion/testData/basic/custom/SamAdapterSrc/JavaClass.java b/idea/idea-completion/testData/basic/custom/SamAdapterSrc/JavaClass.java new file mode 100644 index 00000000000..3e9302d2099 --- /dev/null +++ b/idea/idea-completion/testData/basic/custom/SamAdapterSrc/JavaClass.java @@ -0,0 +1,5 @@ +package lib; + +public class JavaClass { + public void execute(Runnable runnable, int x) {} +} 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 d5848e98796..5196de058a1 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,9 +47,15 @@ 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"); + @TestMetadata("SamAdapter.kt") + public void testSamAdapter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/custom/SamAdapter.kt"); + doTest(fileName); + } + + @TestMetadata("SamAdapterAndGenerics.kt") + public void testSamAdapterAndGenerics() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/custom/SamAdapterAndGenerics.kt"); doTest(fileName); }