diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt index 00d761ffd7f..6f3c7b17958 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/SuperClassNotInitialized.kt @@ -22,7 +22,6 @@ import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project -import com.intellij.psi.PsiFile import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor @@ -38,10 +37,12 @@ import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.types.IndexedParametersSubstitution import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf +import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* public object SuperClassNotInitialized : JetIntentionActionsFactory() { @@ -92,7 +93,7 @@ public object SuperClassNotInitialized : JetIntentionActionsFactory() { val typesRendered = types.take(maxParamsToDisplay).map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it) } val parameterString = typesRendered.joinToString(", ", "(", if (types.size() <= maxParamsToDisplay) ")" else ",...)") val text = "Add constructor parameters from " + superClass.getName().asString() + parameterString - fixes.add(AddParametersFix(delegator, classOrObjectDeclaration, constructor, text)) + fixes.addIfNotNull(AddParametersFix.create(delegator, classOrObjectDeclaration, constructor, text)) } } } @@ -127,56 +128,70 @@ public object SuperClassNotInitialized : JetIntentionActionsFactory() { private class AddParametersFix( element: JetDelegatorToSuperClass, - val classDeclaration: JetClass, - val superConstructor: ConstructorDescriptor, //TODO: do not hold descriptor! + private val classDeclaration: JetClass, + private val parametersToAdd: Collection, + private val argumentText: String, private val text: String ) : KotlinQuickFixAction(element) { - override fun getFamilyName() = "Add constructor parameters from superclass" + companion object { + fun create( + element: JetDelegatorToSuperClass, + classDeclaration: JetClass, + superConstructor: ConstructorDescriptor, + text: String + ): AddParametersFix? { + val superParameters = superConstructor.getValueParameters() + assert(superParameters.isNotEmpty()) - override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { - return super.isAvailable(project, editor, file) && superConstructor.getValueParameters().none { it.getType().isError() } + if (superParameters.any { it.type.isError }) return null + + val argumentText = StringBuilder() + val oldParameters = classDeclaration.getPrimaryConstructorParameters() + val parametersToAdd = ArrayList() + for (parameter in superParameters) { + val nameRendered = parameter.name.render() + val varargElementType = parameter.varargElementType + + if (argumentText.length > 0) { + argumentText.append(", ") + } + argumentText.append(if (varargElementType != null) "*$nameRendered" else nameRendered) + + val nameString = parameter.getName().asString() + val existingParameter = oldParameters.firstOrNull { it.getName() == nameString } + if (existingParameter != null) { + val type = (existingParameter.resolveToDescriptor() as ValueParameterDescriptor).getType() + if (type.isSubtypeOf(parameter.getType())) continue // use existing parameter + } + + val parameterText = if (varargElementType != null) + "vararg " + nameRendered + ":" + IdeDescriptorRenderers.SOURCE_CODE.renderType(varargElementType) + else + nameRendered + ":" + IdeDescriptorRenderers.SOURCE_CODE.renderType(parameter.type) + parametersToAdd.add(JetPsiFactory(element).createParameter(parameterText)) + } + + return AddParametersFix(element, classDeclaration, parametersToAdd, argumentText.toString(), text) + } } - override fun getText()= text + override fun getFamilyName() = "Add constructor parameters from superclass" + + override fun getText() = text override fun invoke(project: Project, editor: Editor?, file: JetFile) { val factory = JetPsiFactory(project) - val renderer = IdeDescriptorRenderers.SOURCE_CODE - val superParameters = superConstructor.getValueParameters() - assert(superParameters.isNotEmpty()) - val parameterNames = ArrayList() val typeRefsToShorten = ArrayList() val parameterList = classDeclaration.createPrimaryConstructorParameterListIfAbsent() - val oldParameters = parameterList.getParameters() - val parametersToAdd = ArrayList() - for (parameter in superParameters) { - val name = renderer.renderName(parameter.getName()) - val varargElementType = parameter.getVarargElementType() - - parameterNames.add(if (varargElementType != null) "*$name" else name) - - val nameString = parameter.getName().asString() - val existingParameter = oldParameters.firstOrNull { it.getName() == nameString } - if (existingParameter != null) { - val type = (existingParameter.resolveToDescriptor() as ValueParameterDescriptor).getType() - if (type.isSubtypeOf(parameter.getType())) continue // use existing parameter - } - - val parameterText = if (varargElementType != null) - "vararg " + name + ":" + renderer.renderType(varargElementType) - else - name + ":" + renderer.renderType(parameter.getType()) - parametersToAdd.add(factory.createParameter(parameterText)) - } for (parameter in parametersToAdd) { val newParameter = parameterList.addParameter(parameter) - typeRefsToShorten.add(newParameter.getTypeReference()!!) + typeRefsToShorten.add(newParameter.typeReference!!) } - val delegatorCall = factory.createDelegatorToSuperCall(element.getText() + "(" + parameterNames.joinToString(",") + ")") + val delegatorCall = factory.createDelegatorToSuperCall(element.text + "(" + argumentText + ")") element.replace(delegatorCall) ShortenReferences.DEFAULT.process(typeRefsToShorten)