Create From Usage: Add support of get/set functions in property delegates
#KT-5977 Fixed
This commit is contained in:
@@ -658,6 +658,11 @@ public class KotlinBuiltIns {
|
|||||||
return getAnnotation().getDefaultType();
|
return getAnnotation().getDefaultType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public ClassDescriptor getPropertyMetadata() {
|
||||||
|
return getBuiltInClassByName("PropertyMetadata");
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ClassDescriptor getPropertyMetadataImpl() {
|
public ClassDescriptor getPropertyMetadataImpl() {
|
||||||
return getBuiltInClassByName("PropertyMetadataImpl");
|
return getBuiltInClassByName("PropertyMetadataImpl");
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ map.platform.class.to.kotlin.multiple=Change all usages of ''{0}'' in this file
|
|||||||
map.platform.class.to.kotlin.advertisement=Choose an appropriate Kotlin class
|
map.platform.class.to.kotlin.advertisement=Choose an appropriate Kotlin class
|
||||||
map.platform.class.to.kotlin.family=Change to Kotlin class
|
map.platform.class.to.kotlin.family=Change to Kotlin class
|
||||||
create.from.usage.family=Create from usage
|
create.from.usage.family=Create from usage
|
||||||
create.function.from.usage=Create function ''{0}'' from usage
|
create.0.from.usage=Create {0} from usage
|
||||||
create.property.from.usage=Create property ''{0}'' from usage
|
create.property.from.usage=Create property ''{0}'' from usage
|
||||||
create.local.variable.from.usage=Create local variable ''{0}''
|
create.local.variable.from.usage=Create local variable ''{0}''
|
||||||
create.parameter.from.usage=Create parameter ''{0}''
|
create.parameter.from.usage=Create parameter ''{0}''
|
||||||
|
|||||||
@@ -264,5 +264,8 @@ public class QuickFixRegistrar {
|
|||||||
QuickFixes.factories.put(NEXT_NONE_APPLICABLE, CreateNextFunctionActionFactory.INSTANCE$);
|
QuickFixes.factories.put(NEXT_NONE_APPLICABLE, CreateNextFunctionActionFactory.INSTANCE$);
|
||||||
QuickFixes.factories.put(ITERATOR_MISSING, CreateIteratorFunctionActionFactory.INSTANCE$);
|
QuickFixes.factories.put(ITERATOR_MISSING, CreateIteratorFunctionActionFactory.INSTANCE$);
|
||||||
QuickFixes.factories.put(COMPONENT_FUNCTION_MISSING, CreateComponentFunctionActionFactory.INSTANCE$);
|
QuickFixes.factories.put(COMPONENT_FUNCTION_MISSING, CreateComponentFunctionActionFactory.INSTANCE$);
|
||||||
|
|
||||||
|
QuickFixes.factories.put(DELEGATE_SPECIAL_FUNCTION_MISSING, CreatePropertyDelegateAccessorsActionFactory.INSTANCE$);
|
||||||
|
QuickFixes.factories.put(DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, CreatePropertyDelegateAccessorsActionFactory.INSTANCE$);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-27
@@ -101,7 +101,7 @@ fun List<TypeCandidate>.getTypeByRenderedType(renderedType: String): JetType? =
|
|||||||
firstOrNull { it.renderedType == renderedType }?.theType
|
firstOrNull { it.renderedType == renderedType }?.theType
|
||||||
|
|
||||||
class CallableBuilderConfiguration(
|
class CallableBuilderConfiguration(
|
||||||
val callableInfo: CallableInfo,
|
val callableInfos: List<CallableInfo>,
|
||||||
val originalExpression: JetExpression,
|
val originalExpression: JetExpression,
|
||||||
val currentFile: JetFile,
|
val currentFile: JetFile,
|
||||||
val currentEditor: Editor
|
val currentEditor: Editor
|
||||||
@@ -128,6 +128,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
public var placement: CallablePlacement by Delegates.notNull()
|
public var placement: CallablePlacement by Delegates.notNull()
|
||||||
|
|
||||||
|
private val elementsToShorten = ArrayList<JetElement>()
|
||||||
|
|
||||||
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) } }
|
||||||
|
|
||||||
@@ -165,19 +167,27 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildNext(iterator: Iterator<CallableInfo>) {
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
val context = Context(iterator.next())
|
||||||
|
runWriteAction { context.buildAndRunTemplate { buildNext(iterator) } }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ShortenReferences.process(elementsToShorten)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun build() {
|
fun build() {
|
||||||
try {
|
try {
|
||||||
if (finished) throw IllegalStateException("Current builder has already finished")
|
if (finished) throw IllegalStateException("Current builder has already finished")
|
||||||
|
buildNext(config.callableInfos.iterator())
|
||||||
val context = Context()
|
|
||||||
runWriteAction { context.buildAndRunTemplate() }
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
finished = true
|
finished = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Context {
|
private inner class Context(val callableInfo: CallableInfo) {
|
||||||
val skipReturnType: Boolean
|
val skipReturnType: Boolean
|
||||||
val isExtension: Boolean
|
val isExtension: Boolean
|
||||||
val containingFile: JetFile
|
val containingFile: JetFile
|
||||||
@@ -231,12 +241,13 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val substitutions = ownerTypeArguments.zip(classTypeParameters).map {
|
val substitutions = ownerTypeArguments.zip(classTypeParameters).map {
|
||||||
JetTypeSubstitution(it.first.getType(), it.second.getType())
|
JetTypeSubstitution(it.first.getType(), it.second.getType())
|
||||||
}.copyToArray()
|
}.copyToArray()
|
||||||
config.callableInfo.parameterInfos.forEach {
|
|
||||||
|
callableInfo.parameterInfos.forEach {
|
||||||
computeTypeCandidates(it.typeInfo, substitutions, scope)
|
computeTypeCandidates(it.typeInfo, substitutions, scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
val returnTypeCandidates = computeTypeCandidates(config.callableInfo.returnTypeInfo, substitutions, scope)
|
val returnTypeCandidates = computeTypeCandidates(callableInfo.returnTypeInfo, substitutions, scope)
|
||||||
skipReturnType = config.callableInfo is FunctionInfo
|
skipReturnType = callableInfo is FunctionInfo
|
||||||
&& returnTypeCandidates.size == 1
|
&& returnTypeCandidates.size == 1
|
||||||
&& returnTypeCandidates.first().theType.isUnit()
|
&& returnTypeCandidates.first().theType.isUnit()
|
||||||
|
|
||||||
@@ -245,9 +256,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
// figure out type parameter renames to avoid conflicts
|
// figure out type parameter renames to avoid conflicts
|
||||||
typeParameterNameMap = getTypeParameterRenames(scope)
|
typeParameterNameMap = getTypeParameterRenames(scope)
|
||||||
config.callableInfo.parameterInfos.forEach { renderTypeCandidates(it.typeInfo, typeParameterNameMap) }
|
callableInfo.parameterInfos.forEach { renderTypeCandidates(it.typeInfo, typeParameterNameMap) }
|
||||||
if (!skipReturnType) {
|
if (!skipReturnType) {
|
||||||
renderTypeCandidates(config.callableInfo.returnTypeInfo, typeParameterNameMap)
|
renderTypeCandidates(callableInfo.returnTypeInfo, typeParameterNameMap)
|
||||||
}
|
}
|
||||||
receiverTypeCandidate?.render(typeParameterNameMap)
|
receiverTypeCandidate?.render(typeParameterNameMap)
|
||||||
}
|
}
|
||||||
@@ -262,7 +273,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
private fun createDeclarationSkeleton(): JetCallableDeclaration {
|
private fun createDeclarationSkeleton(): JetCallableDeclaration {
|
||||||
with (config) {
|
with (config) {
|
||||||
val assignmentToReplace =
|
val assignmentToReplace =
|
||||||
if (containingElement is JetBlockExpression && (config.callableInfo as? PropertyInfo)?.writable ?: false) {
|
if (containingElement is JetBlockExpression && (callableInfo as? PropertyInfo)?.writable ?: false) {
|
||||||
originalExpression as JetBinaryExpression
|
originalExpression as JetBinaryExpression
|
||||||
}
|
}
|
||||||
else null
|
else null
|
||||||
@@ -367,13 +378,13 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
allTypeParametersNotInScope.addAll(receiverTypeCandidate?.typeParameters?.toList() ?: Collections.emptyList())
|
allTypeParametersNotInScope.addAll(receiverTypeCandidate?.typeParameters?.toList() ?: Collections.emptyList())
|
||||||
|
|
||||||
config.callableInfo.parameterInfos.stream()
|
callableInfo.parameterInfos.stream()
|
||||||
.flatMap { typeCandidates[it.typeInfo]!!.stream() }
|
.flatMap { typeCandidates[it.typeInfo]!!.stream() }
|
||||||
.flatMap { it.typeParameters.stream() }
|
.flatMap { it.typeParameters.stream() }
|
||||||
.toCollection(allTypeParametersNotInScope)
|
.toCollection(allTypeParametersNotInScope)
|
||||||
|
|
||||||
if (!skipReturnType) {
|
if (!skipReturnType) {
|
||||||
computeTypeCandidates(config.callableInfo.returnTypeInfo).stream().flatMapTo(allTypeParametersNotInScope) { it.typeParameters.stream() }
|
computeTypeCandidates(callableInfo.returnTypeInfo).stream().flatMapTo(allTypeParametersNotInScope) { it.typeParameters.stream() }
|
||||||
}
|
}
|
||||||
|
|
||||||
val validator = CollectingValidator { scope.getClassifier(Name.identifier(it)) == null }
|
val validator = CollectingValidator { scope.getClassifier(Name.identifier(it)) == null }
|
||||||
@@ -383,7 +394,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupTypeReferencesForShortening(declaration: JetCallableDeclaration,
|
private fun setupTypeReferencesForShortening(declaration: JetCallableDeclaration,
|
||||||
typeRefsToShorten: MutableList<JetTypeReference>,
|
typeRefsToShorten: MutableList<JetElement>,
|
||||||
parameterTypeExpressions: List<TypeExpression>) {
|
parameterTypeExpressions: List<TypeExpression>) {
|
||||||
if (isExtension) {
|
if (isExtension) {
|
||||||
val receiverTypeRef = JetPsiFactory(declaration).createType(receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap))
|
val receiverTypeRef = JetPsiFactory(declaration).createType(receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap))
|
||||||
@@ -397,7 +408,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
val returnTypeRef = declaration.getTypeReference()
|
val returnTypeRef = declaration.getTypeReference()
|
||||||
if (returnTypeRef != null) {
|
if (returnTypeRef != null) {
|
||||||
val returnType = typeCandidates[config.callableInfo.returnTypeInfo]!!.getTypeByRenderedType(
|
val returnType = typeCandidates[callableInfo.returnTypeInfo]!!.getTypeByRenderedType(
|
||||||
returnTypeRef.getText()
|
returnTypeRef.getText()
|
||||||
?: throw AssertionError("Expression for return type shouldn't be empty: declaration = ${declaration.getText()}")
|
?: throw AssertionError("Expression for return type shouldn't be empty: declaration = ${declaration.getText()}")
|
||||||
)
|
)
|
||||||
@@ -440,7 +451,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(it).asString())
|
properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(it).asString())
|
||||||
properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, it.getName().asString())
|
properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, it.getName().asString())
|
||||||
}
|
}
|
||||||
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, config.callableInfo.name)
|
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, callableInfo.name)
|
||||||
|
|
||||||
val bodyText = try {
|
val bodyText = try {
|
||||||
fileTemplate!!.getText(properties)
|
fileTemplate!!.getText(properties)
|
||||||
@@ -460,7 +471,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
private fun setupReturnTypeTemplate(builder: TemplateBuilder, declaration: JetCallableDeclaration): TypeExpression? {
|
private fun setupReturnTypeTemplate(builder: TemplateBuilder, declaration: JetCallableDeclaration): TypeExpression? {
|
||||||
val returnTypeRef = declaration.getTypeReference() ?: return null
|
val returnTypeRef = declaration.getTypeReference() ?: return null
|
||||||
val candidates = typeCandidates[config.callableInfo.returnTypeInfo]!!
|
val candidates = typeCandidates[callableInfo.returnTypeInfo]!!
|
||||||
return when (candidates.size) {
|
return when (candidates.size) {
|
||||||
0 -> null
|
0 -> null
|
||||||
|
|
||||||
@@ -478,7 +489,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupValVarTemplate(builder: TemplateBuilder, property: JetProperty) {
|
private fun setupValVarTemplate(builder: TemplateBuilder, property: JetProperty) {
|
||||||
if (!(config.callableInfo as PropertyInfo).writable) {
|
if (!(callableInfo as PropertyInfo).writable) {
|
||||||
builder.replaceElement(property.getValOrVarNode().getPsi()!!, ValVarExpression)
|
builder.replaceElement(property.getValOrVarNode().getPsi()!!, ValVarExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -487,12 +498,12 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val typeParameterMap = HashMap<String, Array<String>>()
|
val typeParameterMap = HashMap<String, Array<String>>()
|
||||||
val receiverTypeParameterNames = receiverTypeCandidate?.let { it.typeParameterNames!! } ?: ArrayUtil.EMPTY_STRING_ARRAY
|
val receiverTypeParameterNames = receiverTypeCandidate?.let { it.typeParameterNames!! } ?: ArrayUtil.EMPTY_STRING_ARRAY
|
||||||
|
|
||||||
config.callableInfo.parameterInfos.stream().flatMap { typeCandidates[it.typeInfo]!!.stream() }.forEach {
|
callableInfo.parameterInfos.stream().flatMap { typeCandidates[it.typeInfo]!!.stream() }.forEach {
|
||||||
typeParameterMap[it.renderedType!!] = it.typeParameterNames!!
|
typeParameterMap[it.renderedType!!] = it.typeParameterNames!!
|
||||||
}
|
}
|
||||||
|
|
||||||
if (declaration.getTypeReference() != null) {
|
if (declaration.getTypeReference() != null) {
|
||||||
typeCandidates[config.callableInfo.returnTypeInfo]!!.forEach {
|
typeCandidates[callableInfo.returnTypeInfo]!!.forEach {
|
||||||
typeParameterMap[it.renderedType!!] = it.typeParameterNames!!
|
typeParameterMap[it.renderedType!!] = it.typeParameterNames!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,10 +513,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupParameterTypeTemplates(builder: TemplateBuilder, parameterList: List<JetParameter>): List<TypeExpression> {
|
private fun setupParameterTypeTemplates(builder: TemplateBuilder, parameterList: List<JetParameter>): List<TypeExpression> {
|
||||||
assert(parameterList.size == config.callableInfo.parameterInfos.size)
|
assert(parameterList.size == callableInfo.parameterInfos.size)
|
||||||
|
|
||||||
val typeParameters = ArrayList<TypeExpression>()
|
val typeParameters = ArrayList<TypeExpression>()
|
||||||
for ((parameter, jetParameter) in config.callableInfo.parameterInfos.zip(parameterList)) {
|
for ((parameter, jetParameter) in callableInfo.parameterInfos.zip(parameterList)) {
|
||||||
val parameterTypeExpression = TypeExpression(typeCandidates[parameter.typeInfo]!!)
|
val parameterTypeExpression = TypeExpression(typeCandidates[parameter.typeInfo]!!)
|
||||||
val parameterTypeRef = jetParameter.getTypeReference()!!
|
val parameterTypeRef = jetParameter.getTypeReference()!!
|
||||||
builder.replaceElement(parameterTypeRef, parameterTypeExpression)
|
builder.replaceElement(parameterTypeRef, parameterTypeExpression)
|
||||||
@@ -542,7 +553,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
typeRef.replace(fullyQualifiedReceiverTypeRef)
|
typeRef.replace(fullyQualifiedReceiverTypeRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildAndRunTemplate() {
|
// build templates
|
||||||
|
fun buildAndRunTemplate(onFinish: () -> Unit) {
|
||||||
val declarationSkeleton = createDeclarationSkeleton()
|
val declarationSkeleton = createDeclarationSkeleton()
|
||||||
val project = declarationSkeleton.getProject()
|
val project = declarationSkeleton.getProject()
|
||||||
val declarationPointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(declarationSkeleton)
|
val declarationPointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(declarationSkeleton)
|
||||||
@@ -576,7 +588,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
// the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it
|
// the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it
|
||||||
val templateImpl = builder.buildInlineTemplate() as TemplateImpl
|
val templateImpl = builder.buildInlineTemplate() as TemplateImpl
|
||||||
val variables = templateImpl.getVariables()!!
|
val variables = templateImpl.getVariables()!!
|
||||||
for (i in 0..(config.callableInfo.parameterInfos.size - 1)) {
|
for (i in 0..(callableInfo.parameterInfos.size - 1)) {
|
||||||
Collections.swap(variables, i * 2, i * 2 + 1)
|
Collections.swap(variables, i * 2, i * 2 + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,7 +608,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val newDeclaration = PsiTreeUtil.findElementOfClassAtOffset(
|
val newDeclaration = PsiTreeUtil.findElementOfClassAtOffset(
|
||||||
containingFile, offset, javaClass<JetCallableDeclaration>(), false
|
containingFile, offset, javaClass<JetCallableDeclaration>(), false
|
||||||
)!!
|
)!!
|
||||||
val typeRefsToShorten = ArrayList<JetTypeReference>()
|
|
||||||
|
|
||||||
ApplicationManager.getApplication()!!.runWriteAction {
|
ApplicationManager.getApplication()!!.runWriteAction {
|
||||||
// file templates
|
// file templates
|
||||||
@@ -605,9 +616,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// change short type names to fully qualified ones (to be shortened below)
|
// change short type names to fully qualified ones (to be shortened below)
|
||||||
setupTypeReferencesForShortening(newDeclaration, typeRefsToShorten, parameterTypeExpressions)
|
setupTypeReferencesForShortening(newDeclaration, elementsToShorten, parameterTypeExpressions)
|
||||||
ShortenReferences.process(typeRefsToShorten)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFinish()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-8
@@ -10,24 +10,42 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
|
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil
|
||||||
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
import org.jetbrains.jet.lang.psi.JetClassOrObject
|
||||||
import org.jetbrains.jet.plugin.refactoring.chooseContainerElementIfNecessary
|
import org.jetbrains.jet.plugin.refactoring.chooseContainerElementIfNecessary
|
||||||
import org.jetbrains.jet.plugin.refactoring.getExtractionContainers
|
|
||||||
import org.jetbrains.jet.lang.psi.JetClassBody
|
import org.jetbrains.jet.lang.psi.JetClassBody
|
||||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.*
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.*
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.utils.addToStdlib.singletonOrEmptyList
|
||||||
|
|
||||||
public class CreateCallableFromUsageFix(
|
public class CreateCallableFromUsageFix(
|
||||||
originalExpression: JetExpression,
|
originalExpression: JetExpression,
|
||||||
val callableInfo: CallableInfo) : CreateFromUsageFixBase(originalExpression) {
|
val callableInfos: List<CallableInfo>) : CreateFromUsageFixBase(originalExpression) {
|
||||||
override fun getText(): String {
|
{
|
||||||
val key = when (callableInfo.kind) {
|
if (callableInfos.size > 1) {
|
||||||
CallableKind.FUNCTION -> "create.function.from.usage"
|
val callableInfo = callableInfos.first()
|
||||||
CallableKind.PROPERTY -> "create.property.from.usage"
|
|
||||||
|
val receiver = callableInfo.receiverTypeInfo
|
||||||
|
if (!callableInfos.all { it.receiverTypeInfo == receiver }) throw AssertionError("All functions must have common receiver")
|
||||||
|
|
||||||
|
val containers = callableInfo.possibleContainers
|
||||||
|
if (!callableInfos.all { it.possibleContainers == containers }) throw AssertionError("All functions must have common containers")
|
||||||
}
|
}
|
||||||
return JetBundle.message(key, callableInfo.name)
|
}
|
||||||
|
|
||||||
|
override fun getText(): String {
|
||||||
|
val renderedCallables = callableInfos.map {
|
||||||
|
val kind = when (it.kind) {
|
||||||
|
CallableKind.FUNCTION -> "function"
|
||||||
|
CallableKind.PROPERTY -> "property"
|
||||||
|
}
|
||||||
|
"$kind '${it.name}'"
|
||||||
|
}
|
||||||
|
|
||||||
|
return JetBundle.message("create.0.from.usage", renderedCallables.joinToString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
||||||
val callableBuilder = CallableBuilderConfiguration(callableInfo, element as JetExpression, file!!, editor!!).createBuilder()
|
val callableInfo = callableInfos.firstOrNull() ?: return
|
||||||
|
|
||||||
|
val callableBuilder = CallableBuilderConfiguration(callableInfos, element as JetExpression, file!!, editor!!).createBuilder()
|
||||||
|
|
||||||
fun runBuilder(placement: CallablePlacement) {
|
fun runBuilder(placement: CallablePlacement) {
|
||||||
callableBuilder.placement = placement
|
callableBuilder.placement = placement
|
||||||
@@ -59,3 +77,10 @@ public class CreateCallableFromUsageFix(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun CreateCallableFromUsageFix(
|
||||||
|
originalExpression: JetExpression,
|
||||||
|
callableInfo: CallableInfo
|
||||||
|
) : CreateCallableFromUsageFix {
|
||||||
|
return CreateCallableFromUsageFix(originalExpression, callableInfo.singletonOrEmptyList())
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package org.jetbrains.jet.plugin.quickfix.createFromUsage.createFunction
|
||||||
|
|
||||||
|
import org.jetbrains.jet.plugin.quickfix.JetSingleIntentionActionFactory
|
||||||
|
import org.jetbrains.jet.lang.diagnostics.Diagnostic
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||||
|
import org.jetbrains.jet.lang.types.Variance
|
||||||
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||||
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||||
|
import org.jetbrains.jet.lang.psi.JetProperty
|
||||||
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||||
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
|
||||||
|
import org.jetbrains.jet.lang.psi.JetExpression
|
||||||
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||||
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||||
|
import com.intellij.util.SmartList
|
||||||
|
import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor
|
||||||
|
|
||||||
|
object CreatePropertyDelegateAccessorsActionFactory : JetSingleIntentionActionFactory() {
|
||||||
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
|
val expression = diagnostic.getPsiElement() as? JetExpression ?: return null
|
||||||
|
val context = AnalyzerFacadeWithCache.getContextForElement(expression)
|
||||||
|
[suppress("UNCHECKED_CAST")]
|
||||||
|
|
||||||
|
fun isApplicableForAccessor(accessor: PropertyAccessorDescriptor?): Boolean =
|
||||||
|
accessor != null && context[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor] == null
|
||||||
|
|
||||||
|
val builtIns = KotlinBuiltIns.getInstance()
|
||||||
|
|
||||||
|
val property = expression.getParentByType(javaClass<JetProperty>()) ?: return null
|
||||||
|
val propertyDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? PropertyDescriptor
|
||||||
|
?: return null
|
||||||
|
|
||||||
|
val propertyReceiver = propertyDescriptor.getExtensionReceiverParameter() ?: propertyDescriptor.getDispatchReceiverParameter()
|
||||||
|
val propertyType = propertyDescriptor.getType()
|
||||||
|
|
||||||
|
val accessorReceiverType = TypeInfo(expression, Variance.IN_VARIANCE)
|
||||||
|
val thisRefParam = ParameterInfo(TypeInfo(propertyReceiver?.getType() ?: builtIns.getNullableNothingType(), Variance.IN_VARIANCE))
|
||||||
|
val metadataParam = ParameterInfo(TypeInfo(builtIns.getPropertyMetadata().getDefaultType(), Variance.IN_VARIANCE))
|
||||||
|
|
||||||
|
val callableInfos = SmartList<CallableInfo>()
|
||||||
|
|
||||||
|
if (isApplicableForAccessor(propertyDescriptor.getGetter())) {
|
||||||
|
val getterInfo = FunctionInfo(
|
||||||
|
name = "get",
|
||||||
|
receiverTypeInfo = accessorReceiverType,
|
||||||
|
returnTypeInfo = TypeInfo(propertyType, Variance.OUT_VARIANCE),
|
||||||
|
parameterInfos = listOf(thisRefParam, metadataParam)
|
||||||
|
)
|
||||||
|
callableInfos.add(getterInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propertyDescriptor.isVar() && isApplicableForAccessor(propertyDescriptor.getSetter())) {
|
||||||
|
val newValueParam = ParameterInfo(TypeInfo(propertyType, Variance.IN_VARIANCE))
|
||||||
|
val setterInfo = FunctionInfo(
|
||||||
|
name = "set",
|
||||||
|
receiverTypeInfo = accessorReceiverType,
|
||||||
|
returnTypeInfo = TypeInfo(builtIns.getUnitType(), Variance.OUT_VARIANCE),
|
||||||
|
parameterInfos = listOf(thisRefParam, metadataParam, newValueParam)
|
||||||
|
)
|
||||||
|
callableInfos.add(setterInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateCallableFromUsageFix(expression, callableInfos)
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.psi.JetClassBody
|
|||||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.PropertyInfo
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.PropertyInfo
|
||||||
import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
|
import org.jetbrains.jet.lang.psi.psiUtil.getAssignmentByLHS
|
||||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
|
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.getExpressionForTypeGuess
|
||||||
|
import org.jetbrains.jet.utils.addToStdlib.singletonOrEmptyList
|
||||||
|
|
||||||
object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
|
object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
@@ -50,7 +51,7 @@ object CreateLocalVariableActionFactory: JetSingleIntentionActionFactory() {
|
|||||||
override fun getText(): String = JetBundle.message("create.local.variable.from.usage", propertyInfo.name)
|
override fun getText(): String = JetBundle.message("create.local.variable.from.usage", propertyInfo.name)
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
||||||
with (CallableBuilderConfiguration(propertyInfo, assignment ?: refExpr, file!!, editor!!).createBuilder()) {
|
with (CallableBuilderConfiguration(propertyInfo.singletonOrEmptyList(), assignment ?: refExpr, file!!, editor!!).createBuilder()) {
|
||||||
val actualContainer = when (container) {
|
val actualContainer = when (container) {
|
||||||
is JetBlockExpression -> container
|
is JetBlockExpression -> container
|
||||||
else -> ConvertToBlockBodyAction().convert(container as JetDeclarationWithBody).getBodyExpression()!!
|
else -> ConvertToBlockBodyAction().convert(container as JetDeclarationWithBody).getBodyExpression()!!
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// "Create function 'get' from usage" "true"
|
||||||
|
class F {
|
||||||
|
fun get(x: X, propertyMetadata: PropertyMetadata): Int {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
val f: Int by F()
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// "Create function 'get', function 'set' from usage" "true"
|
||||||
|
class F {
|
||||||
|
fun get(x: X, propertyMetadata: PropertyMetadata): Int {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set(x: X, propertyMetadata: PropertyMetadata, i: Int) {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
var f: Int by F()
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// "Create function 'get' from usage" "true"
|
||||||
|
class F {
|
||||||
|
fun set(x: X, propertyMetadata: PropertyMetadata, i: Int) { }
|
||||||
|
|
||||||
|
fun get(x: X, propertyMetadata: PropertyMetadata): Int {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
var f: Int by F()
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
// "Create function 'set' from usage" "true"
|
||||||
|
class F {
|
||||||
|
fun get(x: X, propertyMetadata: PropertyMetadata): Int = 1
|
||||||
|
|
||||||
|
fun set(x: X, propertyMetadata: PropertyMetadata, i: Int) {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
var f: Int by F()
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create function 'get' from usage" "true"
|
||||||
|
class F {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
val f: Int by F()<caret>
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create function 'get', function 'set' from usage" "true"
|
||||||
|
class F {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
var f: Int by F()<caret>
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create function 'get' from usage" "true"
|
||||||
|
class F {
|
||||||
|
fun set(x: X, propertyMetadata: PropertyMetadata, i: Int) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
var f: Int by F()<caret>
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create function 'set' from usage" "true"
|
||||||
|
class F {
|
||||||
|
fun get(x: X, propertyMetadata: PropertyMetadata): Int = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
var f: Int by F()<caret>
|
||||||
|
}
|
||||||
@@ -628,7 +628,7 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction")
|
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@InnerTestClasses({CreateFunction.BinaryOperations.class, CreateFunction.Call.class, CreateFunction.Component.class, CreateFunction.Get.class, CreateFunction.HasNext.class, CreateFunction.Invoke.class, CreateFunction.Iterator.class, CreateFunction.Next.class, CreateFunction.Set.class, CreateFunction.UnaryOperations.class})
|
@InnerTestClasses({CreateFunction.BinaryOperations.class, CreateFunction.Call.class, CreateFunction.Component.class, CreateFunction.DelegateAccessors.class, CreateFunction.Get.class, CreateFunction.HasNext.class, CreateFunction.Invoke.class, CreateFunction.Iterator.class, CreateFunction.Next.class, CreateFunction.Set.class, CreateFunction.UnaryOperations.class})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class CreateFunction extends AbstractQuickFixTest {
|
public static class CreateFunction extends AbstractQuickFixTest {
|
||||||
public void testAllFilesPresentInCreateFunction() throws Exception {
|
public void testAllFilesPresentInCreateFunction() throws Exception {
|
||||||
@@ -962,6 +962,39 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class DelegateAccessors extends AbstractQuickFixTest {
|
||||||
|
public void testAllFilesPresentInDelegateAccessors() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeVal.kt")
|
||||||
|
public void testVal() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/beforeVal.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeVar.kt")
|
||||||
|
public void testVar() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/beforeVar.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeVarMissingGet.kt")
|
||||||
|
public void testVarMissingGet() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/beforeVarMissingGet.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("beforeVarMissingSet.kt")
|
||||||
|
public void testVarMissingSet() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/delegateAccessors/beforeVarMissingSet.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/get")
|
@TestMetadata("idea/testData/quickfix/createFromUsage/createFunction/get")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
@@ -3432,7 +3465,6 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/beforeTypeMismatchLongNameRuntime.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/typeMismatch/casts/beforeTypeMismatchLongNameRuntime.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/quickfix/typeMismatch/componentFunctionReturnTypeMismatch")
|
@TestMetadata("idea/testData/quickfix/typeMismatch/componentFunctionReturnTypeMismatch")
|
||||||
|
|||||||
Reference in New Issue
Block a user