Create From Usage: Add support of get/set functions in property delegates

#KT-5977 Fixed
This commit is contained in:
Alexey Sedunov
2014-10-17 16:41:12 +04:00
parent d4a9b922e5
commit f5f1aec47b
16 changed files with 283 additions and 55 deletions
@@ -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$);
} }
} }
@@ -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()
} }
}) })
} }
@@ -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())
}
@@ -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)
}
}
@@ -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()
}
@@ -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()
}
@@ -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>
}
@@ -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>
}
@@ -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")