Code Insight: Preserve identifier quotes in "Generate equals()/hashCode()/toString()" actions
#KT-15883 Fixed
This commit is contained in:
+4
-2
@@ -21,12 +21,14 @@ import com.intellij.openapi.application.ApplicationManager
|
|||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiNameIdentifierOwner
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
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.CollectingNameValidator
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.core.insertMembersAfter
|
import org.jetbrains.kotlin.idea.core.insertMembersAfter
|
||||||
@@ -154,7 +156,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
|
|||||||
append('\n')
|
append('\n')
|
||||||
|
|
||||||
variablesForEquals.forEach {
|
variablesForEquals.forEach {
|
||||||
val propName = it.name.asString()
|
val propName = (DescriptorToSourceUtilsIde.getAnyDeclaration(project, it) as PsiNameIdentifierOwner).nameIdentifier!!.text
|
||||||
val notEquals = when {
|
val notEquals = when {
|
||||||
KotlinBuiltIns.isArray(it.type) || KotlinBuiltIns.isPrimitiveArray(it.type) ->
|
KotlinBuiltIns.isArray(it.type) || KotlinBuiltIns.isPrimitiveArray(it.type) ->
|
||||||
"!java.util.Arrays.equals($propName, $paramName.$propName)"
|
"!java.util.Arrays.equals($propName, $paramName.$propName)"
|
||||||
@@ -178,7 +180,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
|
|||||||
|
|
||||||
private fun generateHashCode(project: Project, info: Info): KtNamedFunction? {
|
private fun generateHashCode(project: Project, info: Info): KtNamedFunction? {
|
||||||
fun VariableDescriptor.genVariableHashCode(parenthesesNeeded: Boolean): String {
|
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 isNullable = TypeUtils.isNullableType(type)
|
||||||
|
|
||||||
val builtIns = builtIns
|
val builtIns = builtIns
|
||||||
|
|||||||
+11
-7
@@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.ui.DialogWrapper
|
import com.intellij.openapi.ui.DialogWrapper
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.psi.PsiNameIdentifierOwner
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
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.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
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.insertMembersAfter
|
||||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
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.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -57,7 +58,8 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
|
|||||||
data class Info(val classDescriptor: ClassDescriptor,
|
data class Info(val classDescriptor: ClassDescriptor,
|
||||||
val variablesToUse: List<VariableDescriptor>,
|
val variablesToUse: List<VariableDescriptor>,
|
||||||
val generateSuperCall: Boolean,
|
val generateSuperCall: Boolean,
|
||||||
val generator: Generator)
|
val generator: Generator,
|
||||||
|
val project: Project)
|
||||||
|
|
||||||
enum class Generator(val text: String) {
|
enum class Generator(val text: String) {
|
||||||
SINGLE_TEMPLATE("Single template") {
|
SINGLE_TEMPLATE("Single template") {
|
||||||
@@ -67,7 +69,7 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
|
|||||||
return buildString {
|
return buildString {
|
||||||
append("return \"${className.quoteIfNeeded()}(")
|
append("return \"${className.quoteIfNeeded()}(")
|
||||||
info.variablesToUse.joinTo(this) {
|
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)}"
|
"$ref=${renderVariableValue(it, ref)}"
|
||||||
}
|
}
|
||||||
append(")")
|
append(")")
|
||||||
@@ -89,7 +91,7 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
|
|||||||
val varIterator = info.variablesToUse.iterator()
|
val varIterator = info.variablesToUse.iterator()
|
||||||
while (varIterator.hasNext()) {
|
while (varIterator.hasNext()) {
|
||||||
val it = varIterator.next()
|
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)}")
|
append("\"$ref=${renderVariableValue(it, ref)}")
|
||||||
if (varIterator.hasNext()) {
|
if (varIterator.hasNext()) {
|
||||||
append(',')
|
append(',')
|
||||||
@@ -152,7 +154,8 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
|
|||||||
val info = Info(classDescriptor,
|
val info = Info(classDescriptor,
|
||||||
properties.map { context[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as VariableDescriptor },
|
properties.map { context[BindingContext.DECLARATION_TO_DESCRIPTOR, it] as VariableDescriptor },
|
||||||
false,
|
false,
|
||||||
Generator.SINGLE_TEMPLATE)
|
Generator.SINGLE_TEMPLATE,
|
||||||
|
project)
|
||||||
return klass.adjuster?.let { it(info) } ?: info
|
return klass.adjuster?.let { it(info) } ?: info
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +175,8 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
|
|||||||
return Info(classDescriptor,
|
return Info(classDescriptor,
|
||||||
chooser.selectedElements?.map { it.descriptor as VariableDescriptor } ?: emptyList(),
|
chooser.selectedElements?.map { it.descriptor as VariableDescriptor } ?: emptyList(),
|
||||||
headerPanel.isGenerateSuperCall,
|
headerPanel.isGenerateSuperCall,
|
||||||
headerPanel.selectedGenerator)
|
headerPanel.selectedGenerator,
|
||||||
|
project)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateToString(project: Project, info: Info): KtNamedFunction? {
|
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 com.intellij.openapi.ui.Messages
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
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.OverrideMemberChooserObject
|
||||||
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
|
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.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -56,6 +58,8 @@ fun getPropertiesToUseInGeneratedMember(classOrObject: KtClassOrObject): List<Kt
|
|||||||
else -> false
|
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>
|
||||||
|
}
|
||||||
+10
@@ -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>
|
||||||
|
}
|
||||||
+5
@@ -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`)"
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -90,6 +90,12 @@ public class GenerateHashCodeAndEqualsActionTestGenerated extends AbstractGenera
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("multipleVars.kt")
|
||||||
public void testMultipleVars() throws Exception {
|
public void testMultipleVars() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/equalsWithHashCode/multipleVars.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/equalsWithHashCode/multipleVars.kt");
|
||||||
|
|||||||
+12
@@ -89,6 +89,12 @@ public class GenerateToStringActionTestGenerated extends AbstractGenerateToStrin
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("multipleVars.kt")
|
||||||
public void testMultipleVars() throws Exception {
|
public void testMultipleVars() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/multipeTemplates/multipleVars.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/multipeTemplates/multipleVars.kt");
|
||||||
@@ -152,6 +158,12 @@ public class GenerateToStringActionTestGenerated extends AbstractGenerateToStrin
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("multipleVars.kt")
|
||||||
public void testMultipleVars() throws Exception {
|
public void testMultipleVars() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/singleTemplate/multipleVars.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/codeInsight/generate/toString/singleTemplate/multipleVars.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user