Create from Usage: Support accessors for local delegated properties

#KT-19730 Fixed
This commit is contained in:
Alexey Sedunov
2018-02-27 20:46:36 +03:00
parent 2eddce57ff
commit 96de29dfcb
7 changed files with 71 additions and 10 deletions
@@ -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<KtElement>()
private fun updateCurrentModule() {
_currentFileModule = config.currentFile.analyzeFullyAndGetResult().moduleDescriptor
}
fun computeTypeCandidates(typeInfo: TypeInfo): List<TypeCandidate> =
typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(this).map { TypeCandidate(it) } }
@@ -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<CallableInfo> {
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<KtProperty>() ?: 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
@@ -0,0 +1,4 @@
// "Create extension function 'String.getValue'" "true"
fun x(parameters: String) {
val n by <caret>parameters
}
@@ -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.
}
@@ -0,0 +1,4 @@
// "Create extension function 'String.getValue', function 'String.setValue'" "true"
fun x(parameters: String) {
var n by <caret>parameters
}
@@ -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.
}
@@ -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");