From 96de29dfcb60c87d4c917d231864cf0bf1693113 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 27 Feb 2018 20:46:36 +0300 Subject: [PATCH] Create from Usage: Support accessors for local delegated properties #KT-19730 Fixed --- .../callableBuilder/CallableBuilder.kt | 21 +++++++++++++------ ...ePropertyDelegateAccessorsActionFactory.kt | 16 ++++++++++---- .../delegateAccessors/localVal.kt | 4 ++++ .../delegateAccessors/localVal.kt.after | 10 +++++++++ .../delegateAccessors/localVar.kt | 4 ++++ .../delegateAccessors/localVar.kt.after | 14 +++++++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 12 +++++++++++ 7 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt.after create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt create mode 100644 idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index 7537193a68c..0c7b585f871 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -41,9 +41,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl -import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult +import org.jetbrains.kotlin.idea.caches.resolve.* import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.imports.importableFqName @@ -138,13 +137,19 @@ sealed class CallablePlacement { class CallableBuilder(val config: CallableBuilderConfiguration) { private var finished: Boolean = false - val currentFileContext: BindingContext + val currentFileContext = config.currentFile.analyzeWithContent() + + private lateinit var _currentFileModule: ModuleDescriptor val currentFileModule: ModuleDescriptor + get() { + if (!_currentFileModule.isValid) { + updateCurrentModule() + } + return _currentFileModule + } init { - val result = config.currentFile.analyzeFullyAndGetResult() - currentFileContext = result.bindingContext - currentFileModule = result.moduleDescriptor + updateCurrentModule() } val pseudocode: Pseudocode? by lazy { config.originalElement.getContainingPseudocode(currentFileContext) } @@ -155,6 +160,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) { private val elementsToShorten = ArrayList() + private fun updateCurrentModule() { + _currentFileModule = config.currentFile.analyzeFullyAndGetResult().moduleDescriptor + } + fun computeTypeCandidates(typeInfo: TypeInfo): List = typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(this).map { TypeCandidate(it) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreatePropertyDelegateAccessorsActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreatePropertyDelegateAccessorsActionFactory.kt index 8f74f16e163..590cd4a8fe7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreatePropertyDelegateAccessorsActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreatePropertyDelegateAccessorsActionFactory.kt @@ -18,10 +18,13 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable import com.intellij.util.SmartList import org.jetbrains.kotlin.builtins.ReflectionTypes -import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.VariableAccessorDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo @@ -45,13 +48,18 @@ object CreatePropertyDelegateAccessorsActionFactory : CreateCallableMemberFromUs override fun extractFixData(element: KtExpression, diagnostic: Diagnostic): List { val context = element.analyze() - fun isApplicableForAccessor(accessor: PropertyAccessorDescriptor?): Boolean = + fun isApplicableForAccessor(accessor: VariableAccessorDescriptor?): Boolean = accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null val property = element.getNonStrictParentOfType() ?: return emptyList() - val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? PropertyDescriptor + val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptorWithAccessors ?: return emptyList() + if (propertyDescriptor is LocalVariableDescriptor + && !element.languageVersionSettings.supportsFeature(LanguageFeature.LocalDelegatedProperties)) { + return emptyList() + } + val propertyReceiver = propertyDescriptor.extensionReceiverParameter ?: propertyDescriptor.dispatchReceiverParameter val propertyType = propertyDescriptor.type diff --git a/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt new file mode 100644 index 00000000000..e4f246dfb39 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt @@ -0,0 +1,4 @@ +// "Create extension function 'String.getValue'" "true" +fun x(parameters: String) { + val n by parameters +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt.after new file mode 100644 index 00000000000..788d8810141 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt.after @@ -0,0 +1,10 @@ +import kotlin.reflect.KProperty + +// "Create extension function 'String.getValue'" "true" +fun x(parameters: String) { + val n by parameters +} + +private operator fun String.getValue(nothing: Nothing?, property: KProperty<*>): Any { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. +} diff --git a/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt new file mode 100644 index 00000000000..637750a7017 --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt @@ -0,0 +1,4 @@ +// "Create extension function 'String.getValue', function 'String.setValue'" "true" +fun x(parameters: String) { + var n by parameters +} \ No newline at end of file diff --git a/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt.after b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt.after new file mode 100644 index 00000000000..b97ffc8ea5b --- /dev/null +++ b/idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt.after @@ -0,0 +1,14 @@ +import kotlin.reflect.KProperty + +// "Create extension function 'String.getValue', function 'String.setValue'" "true" +fun x(parameters: String) { + var n by parameters +} + +private operator fun String.setValue(nothing: Nothing?, property: KProperty<*>, any: Any) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. +} + +private operator fun String.getValue(nothing: Nothing?, property: KProperty<*>): Any { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 7fa450f1549..844f2287fb9 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3571,6 +3571,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("localVal.kt") + public void testLocalVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVal.kt"); + doTest(fileName); + } + + @TestMetadata("localVar.kt") + public void testLocalVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/localVar.kt"); + doTest(fileName); + } + @TestMetadata("val.kt") public void testVal() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/val.kt");