Create from Usage: Support accessors for local delegated properties
#KT-19730 Fixed
This commit is contained in:
+15
-6
@@ -41,9 +41,8 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
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.util.getJavaClassDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.core.*
|
import org.jetbrains.kotlin.idea.core.*
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
@@ -138,13 +137,19 @@ sealed class CallablePlacement {
|
|||||||
class CallableBuilder(val config: CallableBuilderConfiguration) {
|
class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||||
private var finished: Boolean = false
|
private var finished: Boolean = false
|
||||||
|
|
||||||
val currentFileContext: BindingContext
|
val currentFileContext = config.currentFile.analyzeWithContent()
|
||||||
|
|
||||||
|
private lateinit var _currentFileModule: ModuleDescriptor
|
||||||
val currentFileModule: ModuleDescriptor
|
val currentFileModule: ModuleDescriptor
|
||||||
|
get() {
|
||||||
|
if (!_currentFileModule.isValid) {
|
||||||
|
updateCurrentModule()
|
||||||
|
}
|
||||||
|
return _currentFileModule
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val result = config.currentFile.analyzeFullyAndGetResult()
|
updateCurrentModule()
|
||||||
currentFileContext = result.bindingContext
|
|
||||||
currentFileModule = result.moduleDescriptor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val pseudocode: Pseudocode? by lazy { config.originalElement.getContainingPseudocode(currentFileContext) }
|
val pseudocode: Pseudocode? by lazy { config.originalElement.getContainingPseudocode(currentFileContext) }
|
||||||
@@ -155,6 +160,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
private val elementsToShorten = ArrayList<KtElement>()
|
private val elementsToShorten = ArrayList<KtElement>()
|
||||||
|
|
||||||
|
private fun updateCurrentModule() {
|
||||||
|
_currentFileModule = config.currentFile.analyzeFullyAndGetResult().moduleDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
fun computeTypeCandidates(typeInfo: TypeInfo): List<TypeCandidate> =
|
fun computeTypeCandidates(typeInfo: TypeInfo): List<TypeCandidate> =
|
||||||
typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(this).map { TypeCandidate(it) } }
|
typeCandidates.getOrPut(typeInfo) { typeInfo.getPossibleTypes(this).map { TypeCandidate(it) } }
|
||||||
|
|
||||||
|
|||||||
+12
-4
@@ -18,10 +18,13 @@ package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
|||||||
|
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
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.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
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.CallableInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
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> {
|
override fun extractFixData(element: KtExpression, diagnostic: Diagnostic): List<CallableInfo> {
|
||||||
val context = element.analyze()
|
val context = element.analyze()
|
||||||
|
|
||||||
fun isApplicableForAccessor(accessor: PropertyAccessorDescriptor?): Boolean =
|
fun isApplicableForAccessor(accessor: VariableAccessorDescriptor?): Boolean =
|
||||||
accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null
|
accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null
|
||||||
|
|
||||||
val property = element.getNonStrictParentOfType<KtProperty>() ?: return emptyList()
|
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()
|
?: return emptyList()
|
||||||
|
|
||||||
|
if (propertyDescriptor is LocalVariableDescriptor
|
||||||
|
&& !element.languageVersionSettings.supportsFeature(LanguageFeature.LocalDelegatedProperties)) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
val propertyReceiver = propertyDescriptor.extensionReceiverParameter ?: propertyDescriptor.dispatchReceiverParameter
|
val propertyReceiver = propertyDescriptor.extensionReceiverParameter ?: propertyDescriptor.dispatchReceiverParameter
|
||||||
val propertyType = propertyDescriptor.type
|
val propertyType = propertyDescriptor.type
|
||||||
|
|
||||||
|
|||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// "Create extension function 'String.getValue'" "true"
|
||||||
|
fun x(parameters: String) {
|
||||||
|
val n by <caret>parameters
|
||||||
|
}
|
||||||
+10
@@ -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.
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// "Create extension function 'String.getValue', function 'String.setValue'" "true"
|
||||||
|
fun x(parameters: String) {
|
||||||
|
var n by <caret>parameters
|
||||||
|
}
|
||||||
+14
@@ -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);
|
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")
|
@TestMetadata("val.kt")
|
||||||
public void testVal() throws Exception {
|
public void testVal() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/val.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/val.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user