Code Insight: Preserve identifier quotes in "Generate equals()/hashCode()/toString()" actions

#KT-15883 Fixed
This commit is contained in:
Alexey Sedunov
2017-01-23 14:55:36 +03:00
parent 7382d7c7d6
commit 983ad55357
11 changed files with 83 additions and 9 deletions
@@ -21,12 +21,14 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.insertMembersAfter
@@ -154,7 +156,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
append('\n')
variablesForEquals.forEach {
val propName = it.name.asString()
val propName = (DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) as PsiNameIdentifierOwner).nameIdentifier!!.text
val notEquals = when {
KotlinBuiltIns.isArray(it.type) || KotlinBuiltIns.isPrimitiveArray(it.type) ->
"!java.util.Arrays.equals($propName, $paramName.$propName)"
@@ -178,7 +180,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
private fun generateHashCode(project: Project, info: Info): KtNamedFunction? {
fun VariableDescriptor.genVariableHashCode(parenthesesNeeded: Boolean): String {
val ref = name.asString().quoteIfNeeded()
val ref = (DescriptorToSourceUtilsIde.getAnyDeclaration(project, this) as PsiNameIdentifierOwner).nameIdentifier!!.text
val isNullable = TypeUtils.isNullableType(type)
val builtIns = builtIns
@@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -30,11 +31,11 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.insertMembersAfter
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.BindingContext
@@ -57,7 +58,8 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
data class Info(val classDescriptor: ClassDescriptor,
val variablesToUse: List<VariableDescriptor>,
val generateSuperCall: Boolean,
val generator: Generator)
val generator: Generator,
val project: Project)
enum class Generator(val text: String) {
SINGLE_TEMPLATE("Single template") {
@@ -67,7 +69,7 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
return buildString {
append("return \"${className.quoteIfNeeded()}(")
info.variablesToUse.joinTo(this) {
val ref = it.name.asString().quoteIfNeeded()
val ref = (DescriptorToSourceUtilsIde.getAnyDeclaration(info.project, it) as PsiNameIdentifierOwner).nameIdentifier!!.text
"$ref=${renderVariableValue(it, ref)}"
}
append(")")
@@ -89,7 +91,7 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
val varIterator = info.variablesToUse.iterator()
while (varIterator.hasNext()) {
val it = varIterator.next()
val ref = it.name.asString().quoteIfNeeded()
val ref = (DescriptorToSourceUtilsIde.getAnyDeclaration(info.project, it) as PsiNameIdentifierOwner).nameIdentifier!!.text
append("\"$ref=${renderVariableValue(it, ref)}")
if (varIterator.hasNext()) {
append(',')
@@ -152,7 +154,8 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
val info = Info(classDescriptor,
properties.map { context[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as VariableDescriptor },
false,
Generator.SINGLE_TEMPLATE)
Generator.SINGLE_TEMPLATE,
project)
return klass.adjuster?.let { it(info) } ?: info
}
@@ -172,7 +175,8 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
return Info(classDescriptor,
chooser.selectedElements?.map { it.descriptor as VariableDescriptor } ?: emptyList(),
headerPanel.isGenerateSuperCall,
headerPanel.selectedGenerator)
headerPanel.selectedGenerator,
project)
}
private fun generateToString(project: Project, info: Info): KtNamedFunction? {
@@ -22,8 +22,10 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
@@ -56,6 +58,8 @@ fun getPropertiesToUseInGeneratedMember(classOrObject: KtClassOrObject): List<Kt
else -> false
}
}
}.filter {
KotlinNameSuggester.isIdentifier(it.name?.quoteIfNeeded())
}
}
@@ -0,0 +1,3 @@
class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
<caret>
}
@@ -0,0 +1,21 @@
class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Example
if (`in` != other.`in`) return false
if (`cl ass` != other.`cl ass`) return false
if (`valid` != other.`valid`) return false
return true
}
override fun hashCode(): Int {
var result = `in`.hashCode()
result = 31 * result + `cl ass`.hashCode()
result = 31 * result + `valid`.hashCode()
return result
}
}
@@ -0,0 +1,4 @@
// GENERATOR: MULTIPLE_TEMPLATES
class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
<caret>
}
@@ -0,0 +1,10 @@
// GENERATOR: MULTIPLE_TEMPLATES
class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
override fun toString(): String {
return "Example(" +
"`in`='$`in`'," +
"`cl ass`='$`cl ass`'," +
"`valid`=$`valid`" +
")"
}
}
@@ -0,0 +1,3 @@
class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
<caret>
}
@@ -0,0 +1,5 @@
class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
override fun toString(): String {
return "Example(`in`='$`in`', `cl ass`='$`cl ass`', `valid`=$`valid`)"
}
}
@@ -90,6 +90,12 @@ public class GenerateHashCodeAndEqualsActionTestGenerated extends AbstractGenera
doTest(fileName);
}
@TestMetadata("keepQuotes.kt")
public void testKeepQuotes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/equalsWithHashCode/keepQuotes.kt");
doTest(fileName);
}
@TestMetadata("multipleVars.kt")
public void testMultipleVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/equalsWithHashCode/multipleVars.kt");
@@ -89,6 +89,12 @@ public class GenerateToStringActionTestGenerated extends AbstractGenerateToStrin
doTest(fileName);
}
@TestMetadata("keepQuotes.kt")
public void testKeepQuotes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/multipeTemplates/keepQuotes.kt");
doTest(fileName);
}
@TestMetadata("multipleVars.kt")
public void testMultipleVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/multipeTemplates/multipleVars.kt");
@@ -152,6 +158,12 @@ public class GenerateToStringActionTestGenerated extends AbstractGenerateToStrin
doTest(fileName);
}
@TestMetadata("keepQuotes.kt")
public void testKeepQuotes() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/singleTemplate/keepQuotes.kt");
doTest(fileName);
}
@TestMetadata("multipleVars.kt")
public void testMultipleVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/singleTemplate/multipleVars.kt");