Change Signature: Avoid creating parameters from scratch

#KT-15519 Fixed
This commit is contained in:
Alexey Sedunov
2017-04-18 17:49:03 +03:00
parent c305a42128
commit b80fbe1192
11 changed files with 117 additions and 36 deletions
@@ -24,13 +24,26 @@ import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.psi.psiUtil.siblings
private fun createModifierList(text: String, owner: KtModifierListOwner): KtModifierList { private fun KtModifierListOwner.addModifierList(newModifierList: KtModifierList): KtModifierList {
val newModifierList = KtPsiFactory(owner).createModifierList(text) val anchor = firstChild!!
val anchor = owner.firstChild!!
.siblings(forward = true) .siblings(forward = true)
.dropWhile { it is PsiComment || it is PsiWhiteSpace } .dropWhile { it is PsiComment || it is PsiWhiteSpace }
.first() .first()
return owner.addBefore(newModifierList, anchor) as KtModifierList return addBefore(newModifierList, anchor) as KtModifierList
}
private fun createModifierList(text: String, owner: KtModifierListOwner): KtModifierList {
return owner.addModifierList(KtPsiFactory(owner).createModifierList(text))
}
fun KtModifierListOwner.setModifierList(newModifierList: KtModifierList) {
val currentModifierList = modifierList
if (currentModifierList != null) {
currentModifierList.replace(newModifierList)
}
else {
addModifierList(newModifierList)
}
} }
fun addModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken) { fun addModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken) {
@@ -313,3 +313,10 @@ fun KtCallableDeclaration.setReceiverType(type: KotlinType) {
ShortenReferences.DEFAULT.process(receiverTypeReference!!) ShortenReferences.DEFAULT.process(receiverTypeReference!!)
} }
fun KtParameter.setDefaultValue(newDefaultValue: KtExpression): PsiElement? {
defaultValue?.let { return it.replaced(newDefaultValue) }
val psiFactory = KtPsiFactory(this)
val eq = equalsToken ?: add(psiFactory.createEQ())
return addAfter(newDefaultValue, eq) as KtExpression
}
@@ -284,11 +284,11 @@ open class KotlinChangeInfo(
val isLambda = inheritedCallable.declaration is KtFunctionLiteral val isLambda = inheritedCallable.declaration is KtFunctionLiteral
if (isLambda && signatureParameters.size == 1 && !signatureParameters[0].requiresExplicitType(inheritedCallable)) { if (isLambda && signatureParameters.size == 1 && !signatureParameters[0].requiresExplicitType(inheritedCallable)) {
return signatureParameters[0].getDeclarationSignature(0, inheritedCallable) return signatureParameters[0].getDeclarationSignature(0, inheritedCallable).text
} }
return signatureParameters.indices return signatureParameters.indices
.map { i -> signatureParameters[i].getDeclarationSignature(i, inheritedCallable) } .map { i -> signatureParameters[i].getDeclarationSignature(i, inheritedCallable).text }
.joinToString(separator = ", ") .joinToString(separator = ", ")
} }
@@ -65,8 +65,7 @@ class KotlinChangeSignatureData(
name = parameterDescriptor.name.asString(), name = parameterDescriptor.name.asString(),
originalTypeInfo = KotlinTypeInfo(false, parameterType, parameterTypeText), originalTypeInfo = KotlinTypeInfo(false, parameterType, parameterTypeText),
defaultValueForParameter = jetParameter?.defaultValue, defaultValueForParameter = jetParameter?.defaultValue,
valOrVar = jetParameter?.valOrVarKeyword.toValVar(), valOrVar = jetParameter?.valOrVarKeyword.toValVar()
modifierList = jetParameter?.modifierList
) )
} }
} }
@@ -22,11 +22,14 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.compareDescriptors import org.jetbrains.kotlin.idea.core.compareDescriptors
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.core.quoteIfNeeded import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.core.setDefaultValue
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage
import org.jetbrains.kotlin.idea.references.KtReference import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.addRemoveModifier.setModifierList
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -186,7 +189,15 @@ class KotlinParameterInfo @JvmOverloads constructor (
return parameter.typeReference != null return parameter.typeReference != null
} }
fun getDeclarationSignature(parameterIndex: Int, inheritedCallable: KotlinCallableDefinitionUsage<*>): String { private fun getOriginalParameter(inheritedCallable: KotlinCallableDefinitionUsage<*>): KtParameter? {
val currentFunction = inheritedCallable.declaration as? KtFunction ?: return null
val originalParameterIndex = if (currentFunction.receiverTypeReference == null) originalIndex else originalIndex - 1
return currentFunction.valueParameters.getOrNull(originalParameterIndex)
}
private fun buildNewParameter(inheritedCallable: KotlinCallableDefinitionUsage<*>, parameterIndex: Int): KtParameter {
val psiFactory = KtPsiFactory(inheritedCallable.project)
val buffer = StringBuilder() val buffer = StringBuilder()
if (modifierList != null) { if (modifierList != null) {
@@ -207,6 +218,35 @@ class KotlinParameterInfo @JvmOverloads constructor (
defaultValueForParameter?.let { buffer.append(" = ").append(it.text) } defaultValueForParameter?.let { buffer.append(" = ").append(it.text) }
} }
return buffer.toString() return psiFactory.createParameter(buffer.toString())
}
fun getDeclarationSignature(parameterIndex: Int, inheritedCallable: KotlinCallableDefinitionUsage<*>): KtParameter {
val originalParameter = getOriginalParameter(inheritedCallable)
?: return buildNewParameter(inheritedCallable, parameterIndex)
val psiFactory = KtPsiFactory(originalParameter)
val newParameter = originalParameter.copied()
modifierList?.let { newParameter.setModifierList(it) }
if (valOrVar != newParameter.valOrVarKeyword.toValVar()) {
newParameter.setValOrVar(valOrVar)
}
val newName = getInheritedName(inheritedCallable)
if (newParameter.name != newName) {
newParameter.setName(newName.quoteIfNeeded())
}
if (newParameter.typeReference != null || requiresExplicitType(inheritedCallable)) {
newParameter.typeReference = psiFactory.createType(renderType(parameterIndex, inheritedCallable))
}
if (!inheritedCallable.isInherited) {
defaultValueForParameter?.let { newParameter.setDefaultValue(it) }
}
return newParameter
} }
} }
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.refactoring.changeSignature
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
enum class KotlinValVar(val keywordName: String) { enum class KotlinValVar(val keywordName: String) {
@@ -44,3 +45,24 @@ fun PsiElement?.toValVar(): KotlinValVar {
else -> throw IllegalArgumentException("Unknown val/var token: " + text) else -> throw IllegalArgumentException("Unknown val/var token: " + text)
} }
} }
fun KtParameter.setValOrVar(valOrVar: KotlinValVar): PsiElement? {
val newKeyword = valOrVar.createKeyword(KtPsiFactory(this))
val currentKeyword = valOrVarKeyword
if (currentKeyword != null) {
return if (newKeyword == null) {
currentKeyword.delete()
null
}
else {
currentKeyword.replace(newKeyword)
}
}
if (newKeyword == null) return null
nameIdentifier?.let { return addBefore(newKeyword, it) }
modifierList?.let { return addAfter(newKeyword, it) }
return addAfter(newKeyword, null)
}
@@ -28,14 +28,11 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.setVisibility import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.idea.core.toKeywordToken import org.jetbrains.kotlin.idea.core.toKeywordToken
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinParameterInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.getCallableSubstitutor
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
import org.jetbrains.kotlin.idea.refactoring.replaceListPsiAndKeepDelimiters import org.jetbrains.kotlin.idea.refactoring.replaceListPsiAndKeepDelimiters
import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.ShortenReferences.Options import org.jetbrains.kotlin.idea.core.ShortenReferences.Options
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
@@ -237,31 +234,15 @@ class KotlinCallableDefinitionUsage<T : PsiElement>(
} }
private fun changeParameter(parameterIndex: Int, parameter: KtParameter, parameterInfo: KotlinParameterInfo) { private fun changeParameter(parameterIndex: Int, parameter: KtParameter, parameterInfo: KotlinParameterInfo) {
val valOrVarKeyword = parameter.valOrVarKeyword parameter.setValOrVar(parameterInfo.valOrVar)
val valOrVar = parameterInfo.valOrVar
val psiFactory = KtPsiFactory(project) val psiFactory = KtPsiFactory(project)
val newKeyword = valOrVar.createKeyword(psiFactory)
if (valOrVarKeyword != null) {
if (newKeyword != null) {
valOrVarKeyword.replace(newKeyword)
}
else {
valOrVarKeyword.delete()
}
}
else if (valOrVar != KotlinValVar.None && newKeyword != null) {
val firstChild = parameter.firstChild
parameter.addBefore(newKeyword, firstChild)
parameter.addBefore(psiFactory.createWhiteSpace(), firstChild)
}
if (parameterInfo.isTypeChanged && parameter.typeReference != null) { if (parameterInfo.isTypeChanged && parameter.typeReference != null) {
val renderedType = parameterInfo.renderType(parameterIndex, this) val renderedType = parameterInfo.renderType(parameterIndex, this)
parameter.typeReference = psiFactory.createType(renderedType) parameter.typeReference = psiFactory.createType(renderedType)
} }
val inheritedName = parameterInfo.getInheritedName(this) val inheritedName = parameterInfo.getInheritedName(this)
if (Name.isValidIdentifier(inheritedName)) { if (Name.isValidIdentifier(inheritedName)) {
val newIdentifier = psiFactory.createIdentifier(inheritedName) val newIdentifier = psiFactory.createIdentifier(inheritedName)
@@ -34,15 +34,12 @@ class KotlinCallerUsage(element: KtNamedDeclaration): KotlinUsageInfo<KtNamedDec
is KtClass -> element.createPrimaryConstructorParameterListIfAbsent() is KtClass -> element.createPrimaryConstructorParameterListIfAbsent()
else -> null else -> null
} ?: return true } ?: return true
val psiFactory = KtPsiFactory(project)
changeInfo.getNonReceiverParameters() changeInfo.getNonReceiverParameters()
.withIndex() .withIndex()
.filter { it.value.isNewParameter } .filter { it.value.isNewParameter }
.forEach { .forEach {
val parameterText = it.value.getDeclarationSignature(it.index, changeInfo.methodDescriptor.originalPrimaryCallable) val newParameter = it.value.getDeclarationSignature(it.index, changeInfo.methodDescriptor.originalPrimaryCallable)
parameterList parameterList.addParameter(newParameter).addToShorteningWaitSet()
.addParameter(psiFactory.createParameter(parameterText))
.addToShorteningWaitSet()
} }
return true return true
@@ -0,0 +1,7 @@
data class <caret>VertexAttribute(
/**
* The number of components this attribute has.
**/
val numComponents: Int
) {}
@@ -0,0 +1,13 @@
data class <caret>VertexAttribute(
/**
* The number of components this attribute has.
**/
val numComponents: Int,
/**
* If true and [type] is not [Gl20.FLOAT], the data will be mapped to the range -1 to 1 for signed types and
* the range 0 to 1 for unsigned types.
*/
val normalized: Boolean
) {}
@@ -942,4 +942,6 @@ class KotlinChangeSignatureTest : KotlinLightCodeInsightFixtureTestCase() {
} }
fun testReceiverInSafeCall() = doTestConflict { receiverParameterInfo = null } fun testReceiverInSafeCall() = doTestConflict { receiverParameterInfo = null }
fun testRemoveParameterKeepOtherComments() = doTest { removeParameter(1) }
} }