From 04b8cf4aa57b81ef15977bcaa4ffe3d64cd5e50b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 13 Jan 2015 12:38:28 +0100 Subject: [PATCH] generate equals/hashCode: allow getters (IDEA-73860) --- .../generation/GenerateEqualsHandler.java | 3 +- .../generation/GenerateEqualsHelper.java | 18 ++- .../generation/apacheEqualsBuilder.vm | 4 +- .../generation/apacheEqualsBuilder3.vm | 4 +- .../generation/apacheHashCodeBuilder.vm | 4 +- .../generation/apacheHashCodeBuilder3.vm | 4 +- .../codeInsight/generation/defaultEquals.vm | 18 +-- .../codeInsight/generation/defaultHashCode.vm | 28 ++-- .../codeInsight/generation/equalsHelper.vm | 4 +- .../codeInsight/generation/guavaEquals.vm | 8 +- .../codeInsight/generation/guavaHashCode.vm | 6 +- .../codeInsight/generation/objectsEquals.vm | 8 +- .../codeInsight/generation/objectsHashCode.vm | 6 +- .../generation/ui/GenerateEqualsWizard.java | 34 +++-- .../afterDifferentTypesGetters.java | 121 ++++++++++++++++++ .../beforeDifferentTypesGetters.java | 69 ++++++++++ .../codeInsight/GenerateEquals15Test.java | 9 ++ .../codeInsight/GenerateEqualsTestCase.java | 17 ++- .../codeInsight/CodeInsightSettings.java | 1 + .../src/messages/CodeInsightBundle.properties | 2 + .../java/generate/GenerationUtil.java | 10 +- .../java/generate/element/Element.java | 5 +- .../java/generate/element/ElementFactory.java | 5 +- .../java/generate/element/ElementUtils.java | 19 ++- .../java/generate/element/FieldElement.java | 9 +- 25 files changed, 337 insertions(+), 79 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesGetters.java create mode 100644 java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesGetters.java diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHandler.java index 352a44e4750f..eb96eef575b1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHandler.java @@ -118,9 +118,10 @@ public class GenerateEqualsHandler extends GenerateMembersHandlerBase { protected List generateMemberPrototypes(PsiClass aClass, ClassMember[] originalMembers) throws IncorrectOperationException { Project project = aClass.getProject(); final boolean useInstanceofToCheckParameterType = CodeInsightSettings.getInstance().USE_INSTANCEOF_ON_EQUALS_PARAMETER; + final boolean useAccessors = CodeInsightSettings.getInstance().USE_ACCESSORS_IN_EQUALS_HASHCODE; GenerateEqualsHelper helper = new GenerateEqualsHelper(project, aClass, myEqualsFields, myHashCodeFields, myNonNullFields, - useInstanceofToCheckParameterType); + useInstanceofToCheckParameterType, useAccessors); return OverrideImplementUtil.convert2GenerationInfos(helper.generateMembers()); } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java index 106733b899a1..d418637f6985 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java @@ -47,18 +47,30 @@ public class GenerateEqualsHelper implements Runnable { private final JavaCodeStyleManager myJavaCodeStyleManager; private final Project myProject; private final boolean myCheckParameterWithInstanceof; + private final boolean myUseAccessors; + + public GenerateEqualsHelper(Project project, + PsiClass aClass, + PsiField[] equalsFields, + PsiField[] hashCodeFields, + PsiField[] nonNullFields, + boolean useInstanceofToCheckParameterType) { + this(project, aClass, equalsFields, hashCodeFields, nonNullFields, useInstanceofToCheckParameterType, false); + } public GenerateEqualsHelper(Project project, PsiClass aClass, PsiField[] equalsFields, PsiField[] hashCodeFields, PsiField[] nonNullFields, - boolean useInstanceofToCheckParameterType) { + boolean useInstanceofToCheckParameterType, + boolean useAccessors) { myClass = aClass; myEqualsFields = equalsFields; myHashCodeFields = hashCodeFields; myProject = project; myCheckParameterWithInstanceof = useInstanceofToCheckParameterType; + myUseAccessors = useAccessors; myNonNullSet = new HashSet(); ContainerUtil.addAll(myNonNullSet, nonNullFields); @@ -157,7 +169,7 @@ public class GenerateEqualsHelper implements Runnable { final String methodText = GenerationUtil .velocityGenerateCode(myClass, equalsFields, myNonNullSet, new HashMap(), contextMap, - EqualsHashCodeTemplatesManager.getInstance().getDefaultEqualsTemplate().getTemplate(), 0, false); + EqualsHashCodeTemplatesManager.getInstance().getDefaultEqualsTemplate().getTemplate(), 0, false, myUseAccessors); buffer.append(methodText); PsiMethod result; try { @@ -196,7 +208,7 @@ public class GenerateEqualsHelper implements Runnable { final String methodText = GenerationUtil .velocityGenerateCode(myClass, Arrays.asList(myHashCodeFields), myNonNullSet, new HashMap(), contextMap, - EqualsHashCodeTemplatesManager.getInstance().getDefaultHashcodeTemplate().getTemplate(), 0, false); + EqualsHashCodeTemplatesManager.getInstance().getDefaultHashcodeTemplate().getTemplate(), 0, false, myUseAccessors); buffer.append(methodText); PsiMethod hashCode; try { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm index 690a223c5d00..40182e77eb90 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm @@ -14,8 +14,8 @@ Object $paramName){ #if($superHasEquals) .appendSuper(super.equals($paramName)) #end - #foreach($field in $members) - .append($field.name, ${classInstanceName}.$field.name) + #foreach($field in $fields) + .append($field.accessor, ${classInstanceName}.$field.accessor) #end .isEquals(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm index dd3fecd94f80..21ece4bc5a89 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm @@ -14,8 +14,8 @@ Object $paramName){ #if($superHasEquals) .appendSuper(super.equals($paramName)) #end - #foreach($field in $members) - .append($field.name, ${classInstanceName}.$field.name) + #foreach($field in $fields) + .append($field.accessor, ${classInstanceName}.$field.accessor) #end .isEquals(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm index db93847c6d3b..5bda0eeb6f20 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm @@ -3,8 +3,8 @@ public int hashCode() { #if($superHasHashCode) .appendSuper(super.hashCode()) #end - #foreach($field in $members) - .append($field.name) + #foreach($field in $fields) + .append($field.accessor) #end .toHashCode(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm index ecb288dc146a..32045dbb0460 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm @@ -3,8 +3,8 @@ public int hashCode() { #if($superHasHashCode) .appendSuper(super.hashCode()) #end - #foreach($field in $members) - .append($field.name) + #foreach($field in $fields) + .append($field.accessor) #end .toHashCode(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm index 94c6c93d4065..8dd207508844 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm @@ -5,11 +5,11 @@ public boolean equals(## #end Object $paramName){ #addEqualsPrologue() -#if ($members.size() > 0) +#if ($fields.size() > 0) #addClassInstance() - #foreach($field in $members) + #foreach($field in $fields) #if ($field.array) #addArrayEquals($field) #elseif ($field.primitive) @@ -30,29 +30,29 @@ Object $paramName){ } ## #macro(addPrimitiveFieldComparison $field) - if($field.name != ${classInstanceName}.$field.name) return false; + if($field.accessor != ${classInstanceName}.$field.accessor) return false; #end ## #macro(addDoubleFieldComparison $field) #if ($field.double) - if(Double.compare(${classInstanceName}.$field.name, $field.name) != 0)return false; + if(Double.compare(${classInstanceName}.$field.accessor, $field.accessor) != 0)return false; #else - if(Float.compare(${classInstanceName}.$field.name, $field.name) != 0)return false; + if(Float.compare(${classInstanceName}.$field.accessor, $field.accessor) != 0)return false; #end #end ## #macro(addFieldComparison $field) #if ($field.notNull) - if(!${field.name}.equals(${classInstanceName}.$field.name))return false; + if(!${field.accessor}.equals(${classInstanceName}.$field.accessor))return false; #else - if($field.name != null ? !${field.name}.equals(${classInstanceName}.$field.name) : ${classInstanceName}.$field.name != null)return false; + if($field.accessor != null ? !${field.accessor}.equals(${classInstanceName}.$field.accessor) : ${classInstanceName}.$field.accessor != null)return false; #end #end ## #macro(addArrayEquals $field) #if ($field.nestedArray) #if ($java_version > 4) - if(!java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)) return false; + if(!java.util.Arrays.deepEquals($field.accessor, ${classInstanceName}.$field.accessor)) return false; #else // Compare nested arrays - values of $field.name here #end @@ -61,5 +61,5 @@ Object $paramName){ #if ($field.objectArray) // Probably incorrect - comparing Object[] arrays with Arrays.equals #end - if(!java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)) return false; + if(!java.util.Arrays.equals($field.accessor, ${classInstanceName}.$field.accessor)) return false; #end \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm index b8e0641d6de7..e4c51becd08c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/defaultHashCode.vm @@ -1,14 +1,14 @@ public int hashCode() { -#if (!$superHasHashCode && $members.size() == 1) - #set($field = $members.get(0)) +#if (!$superHasHashCode && $fields.size() == 1) + #set($field = $fields.get(0)) #if ($field.primitive) #addTempForOneField($field) return #addPrimitiveFieldHashCode($field); #else return #addFieldHashCode($field, false); #end -#elseif ($members.size() > 0) - #set($resultName = $helper.getUniqueLocalVarName("result", $members, $settings)) +#elseif ($fields.size() > 0) + #set($resultName = $helper.getUniqueLocalVarName("result", $fields, $settings)) int $resultName ## #set($resultAssigned = false) #set($resultDeclarationCompleted = false) @@ -19,7 +19,7 @@ public int hashCode() { #end #addTempDeclaration($resultDeclarationCompleted) #set($tempName = "#addTempDeclaration($resultDeclarationCompleted)") - #foreach($field in $members) + #foreach($field in $fields) #addTempAssignment($field) #if ($resultDeclarationCompleted) $resultName ## @@ -44,7 +44,7 @@ public int hashCode() { } ## #macro (addPrimitiveFieldHashCode $field) - #set ($fName = $field.name) + #set ($fName = $field.accessor) #if ($field.byte || $field.short || $field.char) (int) $fName## #elseif ($field.long) @@ -64,7 +64,7 @@ public int hashCode() { #end ## #macro(getTempVarName) - $helper.getUniqueLocalVarName("temp", $members, $settings)## + $helper.getUniqueLocalVarName("temp", $fields, $settings)## #end ## #macro(addTempForOneField $field) @@ -73,7 +73,7 @@ public int hashCode() { final ## #end #set($tempName = "#getTempVarName()") - long $tempName = Double.doubleToLongBits($field.name); + long $tempName = Double.doubleToLongBits($field.accessor); #end #end ## @@ -82,9 +82,9 @@ public int hashCode() { #if ($field.nestedArray) // Probably incorrect - hashCode for high dimension arrays with Arrays.hashCode #end - java.util.Arrays.hashCode($field.name)## + java.util.Arrays.hashCode($field.accessor)## #else - ${field.name}.hashCode()## + ${field.accessor}.hashCode()## #end #end ## @@ -97,8 +97,8 @@ public int hashCode() { #end ## #macro(addTempDeclaration $resultDeclarationCompleted) - #foreach($member in $members) - #if ($member.double) + #foreach($field in $fields) + #if ($field.double) #if (!$resultDeclarationCompleted) ; #end @@ -113,12 +113,12 @@ public int hashCode() { #macro(addTempAssignment $field) #if ($field.double) #set($tempName = "#getTempVarName()") - $tempName = Double.doubleToLongBits($field.name); + $tempName = Double.doubleToLongBits($field.accessor); #end #end ## #macro(addFieldHashCode $field $brace) -#set($name = $field.name) +#set($name = $field.accessor) #if ($field.notNull)#adjustHashCodeToArrays($field) #else #if ($brace)(## diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/equalsHelper.vm b/java/java-impl/src/com/intellij/codeInsight/generation/equalsHelper.vm index 8b8137f19a4e..905d1e40dfa8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/equalsHelper.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/equalsHelper.vm @@ -1,5 +1,5 @@ -#set($classInstanceName = $helper.getUniqueLocalVarName($instanceName, $members, $settings)) -#set($paramName = $helper.getUniqueLocalVarName($baseParamName, $members, $settings)) +#set($classInstanceName = $helper.getUniqueLocalVarName($instanceName, $fields, $settings)) +#set($paramName = $helper.getUniqueLocalVarName($baseParamName, $fields, $settings)) #macro(addClassInstance) #if ($settings.generateFinalLocals) final ## diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm index 213cabdd032d..9869409aff52 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm @@ -8,19 +8,19 @@ Object $paramName){ #addClassInstance() return ## #set($i = 0) - #foreach($field in $members) + #foreach($field in $fields) #if ($i > 0) && #end #set($i = $i + 1) #if ($field.array) #if ($field.nestedArray) -java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)## +java.util.Arrays.deepEquals($field.accessor, ${classInstanceName}.$field.accessor)## #else -java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## +java.util.Arrays.equals($field.accessor, ${classInstanceName}.$field.accessor)## #end #else -com.google.common.base.Objects.equal($field.name, ${classInstanceName}.$field.name)## +com.google.common.base.Objects.equal($field.accessor, ${classInstanceName}.$field.accessor)## #end #end ; diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm index ff5bfcec7fb0..1cd5d480fd8a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm @@ -5,12 +5,12 @@ public int hashCode() { super.hashCode() ## #set($i = 1) #end - #foreach($member in $members) - #if (!$member.static) + #foreach($field in $fields) + #if (!$field.static) #if ($i > 0) , ## #end - $member.name ## + $field.accessor ## #set($i = $i + 1) #end #end diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm index 878a1f7656bd..5e240f9f73d2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm @@ -8,19 +8,19 @@ Object $paramName){ #addClassInstance() return ## #set($i = 0) - #foreach($field in $members) + #foreach($field in $fields) #if ($i > 0) && #end #set($i = $i + 1) #if ($field.array) #if ($field.nestedArray) -java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)## +java.util.Arrays.deepEquals($field.accessor, ${classInstanceName}.$field.accessor)## #else -java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## +java.util.Arrays.equals($field.accessor, ${classInstanceName}.$field.accessor)## #end #else -java.util.Objects.equals($field.name, ${classInstanceName}.$field.name)## +java.util.Objects.equals($field.accessor, ${classInstanceName}.$field.accessor)## #end #end ; diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm index dfe06020b040..b86d346e1011 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm @@ -5,12 +5,12 @@ public int hashCode() { super.hashCode() ## #set($i = 1) #end - #foreach($member in $members) - #if (!$member.static) + #foreach($field in $fields) + #if (!$field.static) #if ($i > 0) , ## #end - $member.name ## + $field.accessor ## #set($i = $i + 1) #end #end diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java b/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java index 5261839f25ad..e2f6c1c3b9d4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java @@ -341,23 +341,15 @@ public class GenerateEqualsWizard extends AbstractGenerateEqualsWizard comboBoxWithBrowseButton = new ComponentWithBrowseButton(comboBox, - new MyEditTemplatesListener(project, myPanel, comboBox)); + final ComponentWithBrowseButton comboBoxWithBrowseButton = + new ComponentWithBrowseButton(comboBox, new MyEditTemplatesListener(project, myPanel, comboBox)); + templateChooserLabel.setLabelFor(comboBox); final EqualsHashCodeTemplatesManager manager = EqualsHashCodeTemplatesManager.getInstance(); comboBox.setModel(new DefaultComboBoxModel(manager.getTemplateNames())); comboBox.setSelectedItem(manager.getDefaultTemplateBaseName()); @@ -369,8 +361,26 @@ public class GenerateEqualsWizard extends AbstractGenerateEqualsWizard>> 32)); + result = 31 * result + (getA11() != +0.0f ? Float.floatToIntBits(getA11()) : 0); + temp = Double.doubleToLongBits(getA12()); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + (a13 != null ? a13.hashCode() : 0); + result = 31 * result + (a14 != null ? a14.hashCode() : 0); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesGetters.java b/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesGetters.java new file mode 100644 index 000000000000..8bf2e28ab919 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesGetters.java @@ -0,0 +1,69 @@ + +class A { + Object[] a1; + Object[][] a2; + String[] a3; + String[][] a4; + int[] a5; + int[][] a6; + + byte a7; + short a8; + int a9; + long a10; + float a11; + double a12; + + Object a13; + String a14; + + public Object[] getA1() { + return a1; + } + + public Object[][] getA2() { + return a2; + } + + public String[] getA3() { + return a3; + } + + public String[][] getA4() { + return a4; + } + + public int[] getA5() { + return a5; + } + + public int[][] getA6() { + return a6; + } + + public byte getA7() { + return a7; + } + + public short getA8() { + return a8; + } + + public int getA9() { + return a9; + } + + public long getA10() { + return a10; + } + + public float getA11() { + return a11; + } + + public double getA12() { + return a12; + } + + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java index 68cd47604a9a..9eae9fd23a9a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java @@ -22,6 +22,15 @@ public class GenerateEquals15Test extends GenerateEqualsTestCase { ); } + public void testDifferentTypesGetters() throws Exception { + doTest(Function.ID, Function.ID, new Function() { + @Override + public PsiField[] fun(PsiField[] fields) { + return new PsiField[0]; + } + }, true, true); + } + public void testDifferentTypesAllNotNull() throws Exception { doTest(Function.ID, Function.ID, Function.ID, true); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java index db1c6ac768e6..cb28ca2ef5a0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEqualsTestCase.java @@ -43,12 +43,23 @@ public abstract class GenerateEqualsTestCase extends LightCodeInsightTestCase { Function hFunction, Function nnFunction, boolean insertOverride) throws Exception { + doTest(eqFunction, hFunction, nnFunction, insertOverride, false); + } + + protected void doTest(Function eqFunction, + Function hFunction, + Function nnFunction, + boolean insertOverride, boolean useAccessors) throws Exception { configureByFile("/codeInsight/generateEquals/before" + getTestName(false) + ".java"); - performTest(eqFunction, hFunction, nnFunction, insertOverride); + performTest(eqFunction, hFunction, nnFunction, insertOverride, useAccessors); checkResultByFile("/codeInsight/generateEquals/after" + getTestName(false) + ".java"); } - private static void performTest(Function equals, Function hashCode, Function nonNull, boolean insertOverride) { + private static void performTest(Function equals, + Function hashCode, + Function nonNull, + boolean insertOverride, + boolean useAccessors) { CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).clone(); settings.GENERATE_FINAL_LOCALS = true; settings.INSERT_OVERRIDE_ANNOTATION = insertOverride; @@ -59,7 +70,7 @@ public abstract class GenerateEqualsTestCase extends LightCodeInsightTestCase { PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); if (aClass == null) return; PsiField[] fields = aClass.getFields(); - new GenerateEqualsHelper(getProject(), aClass, equals.fun(fields), hashCode.fun(fields), nonNull.fun(fields), false).invoke(); + new GenerateEqualsHelper(getProject(), aClass, equals.fun(fields), hashCode.fun(fields), nonNull.fun(fields), false, useAccessors).invoke(); FileDocumentManager.getInstance().saveAllDocuments(); } finally { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java index e1d6271e96db..7a5ceb8ef1d0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java @@ -127,6 +127,7 @@ public class CodeInsightSettings implements PersistentStateComponent, C public boolean HIGHLIGHT_SCOPE = false; public boolean USE_INSTANCEOF_ON_EQUALS_PARAMETER = false; + public boolean USE_ACCESSORS_IN_EQUALS_HASHCODE = false; public boolean HIGHLIGHT_IDENTIFIER_UNDER_CARET = true; diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 72992af11a4f..47588e151c8d 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -97,6 +97,8 @@ generate.equals.hashcode.wizard.title=Generate equals() and hashCode() generate.equals.hashcode.equals.fields.chooser.title=Choose &fields to be included in equals() generate.equals.hashcode.hashcode.fields.chooser.title=Choose &fields to be included in hashCode() generate.equals.hashcode.non.null.fields.chooser.title=Select all non-null &fields +generate.equals.hashcode.use.getters=Use &getters during code generation +generate.equals.hashcode.template=&Template: generate.equals.hashcode.accept.sublcasses=Accept &subclasses as parameter to equals() method generate.equals.hashcode.accept.sublcasses.explanation=While generally incompliant to Object.equals() specification accepting
subclasses might be necessary for generated \ method to work correctly
with frameworks, which generate Proxy subclasses like Hibernate. diff --git a/plugins/generate-tostring/src/org/jetbrains/java/generate/GenerationUtil.java b/plugins/generate-tostring/src/org/jetbrains/java/generate/GenerationUtil.java index 3c972e4e738a..e32df90fe7f0 100644 --- a/plugins/generate-tostring/src/org/jetbrains/java/generate/GenerationUtil.java +++ b/plugins/generate-tostring/src/org/jetbrains/java/generate/GenerationUtil.java @@ -138,7 +138,7 @@ public class GenerationUtil { int sortElements, boolean useFullyQualifiedName) throws GenerateCodeException { - return velocityGenerateCode(clazz, selectedMembers, Collections.emptyList(), params, Collections.emptyMap(), templateMacro, sortElements, useFullyQualifiedName); + return velocityGenerateCode(clazz, selectedMembers, Collections.emptyList(), params, Collections.emptyMap(), templateMacro, sortElements, useFullyQualifiedName, false); } /** @@ -149,6 +149,7 @@ public class GenerationUtil { * @param selectedMembers the selected members as both {@link PsiField} and {@link PsiMethod}. * @param params additional parameters stored with key/value in the map. * @param templateMacro the velocity macro template + * @param useAccessors if true, accessor property for FieldElement bean would be assigned to field getter name append with () * @return code (usually javacode). Returns null if templateMacro is null. * @throws GenerateCodeException is thrown when there is an error generating the javacode. */ @@ -159,7 +160,8 @@ public class GenerationUtil { Map contextMap, String templateMacro, int sortElements, - boolean useFullyQualifiedName) + boolean useFullyQualifiedName, + boolean useAccessors) throws GenerateCodeException { if (templateMacro == null) { return null; @@ -173,7 +175,7 @@ public class GenerationUtil { // field information logger.debug("Velocity Context - adding fields"); - vc.put("fields", ElementUtils.getOnlyAsFieldElements(selectedMembers)); + vc.put("fields", ElementUtils.getOnlyAsFieldElements(selectedMembers, selectedNotNullMembers, useAccessors)); // method information logger.debug("Velocity Context - adding methods"); @@ -181,7 +183,7 @@ public class GenerationUtil { // element information (both fields and methods) logger.debug("Velocity Context - adding members (fields and methods)"); - List elements = ElementUtils.getOnlyAsFieldAndMethodElements(selectedMembers, selectedNotNullMembers); + List elements = ElementUtils.getOnlyAsFieldAndMethodElements(selectedMembers, selectedNotNullMembers, useAccessors); // sort elements if enabled and not using chooser dialog if (sortElements != 0) { Collections.sort(elements, new ElementComparator(sortElements)); diff --git a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/Element.java b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/Element.java index 5619729f8769..fafa5581a51a 100644 --- a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/Element.java +++ b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/Element.java @@ -15,6 +15,8 @@ */ package org.jetbrains.java.generate.element; +import com.intellij.psi.PsiField; + /** * This is an Element. *

@@ -27,7 +29,8 @@ public interface Element { /** * Get's the elements accessor. *

- *
If the element is a field the accessor is just the name of the field - example: myField + *
If the element is a field the accessor is just the of the field or name of it's accessor with () when useAccessor property is on + * {@link ElementFactory#newFieldElement(PsiField, boolean)} - example: myField or getMyField() *
If the element is a method the accessor is the methodname with () - example: getMyField() * * @return the accessor, null if none exists (only for a method with parameters). diff --git a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementFactory.java b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementFactory.java index 693e2278c270..8a88e8502eb5 100644 --- a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementFactory.java +++ b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementFactory.java @@ -17,6 +17,7 @@ package org.jetbrains.java.generate.element; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; +import com.intellij.psi.util.PropertyUtil; import org.jetbrains.java.generate.psi.PsiAdapter; /** @@ -66,9 +67,11 @@ public class ElementFactory { * @param field the {@link com.intellij.psi.PsiField} to get the information from. * @return a new {@link FieldElement} object. */ - public static FieldElement newFieldElement(PsiField field) { + public static FieldElement newFieldElement(PsiField field, boolean useAccessor) { FieldElement fe = new FieldElement(); fe.setName(field.getName()); + final PsiMethod getterForField = useAccessor ? PropertyUtil.findGetterForField(field) : null; + fe.setAccessor(getterForField != null ? getterForField.getName() + "()" : field.getName()); if (PsiAdapter.isConstantField(field)) fe.setConstant(true); if (PsiAdapter.isEnumField(field)) fe.setEnum(true); diff --git a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementUtils.java b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementUtils.java index a7ef483a6b5a..2b40f82acd32 100644 --- a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementUtils.java +++ b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/ElementUtils.java @@ -33,16 +33,23 @@ public class ElementUtils { /** * Gets the list of members to be put in the VelocityContext. * - * @param members a list of {@link com.intellij.psi.PsiMember} objects. + * @param members a list of {@link PsiMember} objects. + * @param selectedNotNullMembers + * @param useAccessors * @return a filtered list of only the fields as {@link FieldElement} objects. */ - public static List getOnlyAsFieldElements(Collection members) { + public static List getOnlyAsFieldElements(Collection members, + Collection selectedNotNullMembers, + boolean useAccessors) { List fieldElementList = new ArrayList(); for (PsiMember member : members) { if (member instanceof PsiField) { PsiField field = (PsiField) member; - FieldElement fe = ElementFactory.newFieldElement(field); + FieldElement fe = ElementFactory.newFieldElement(field, useAccessors); + if (selectedNotNullMembers.contains(member)) { + fe.setNotNull(true); + } fieldElementList.add(fe); } } @@ -75,16 +82,18 @@ public class ElementUtils { * * @param members a list of {@link PsiMember} objects. * @param selectedNotNullMembers a list of @NotNull objects + * @param useAccessors * @return a filtered list of only the methods as a {@link FieldElement} or {@link MethodElement} objects. */ public static List getOnlyAsFieldAndMethodElements(Collection members, - Collection selectedNotNullMembers) { + Collection selectedNotNullMembers, + boolean useAccessors) { List elementList = new ArrayList(); for (PsiMember member : members) { AbstractElement element = null; if (member instanceof PsiField) { - element = ElementFactory.newFieldElement((PsiField) member); + element = ElementFactory.newFieldElement((PsiField) member, useAccessors); } else if (member instanceof PsiMethod) { element = ElementFactory.newMethodElement((PsiMethod) member); } diff --git a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/FieldElement.java b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/FieldElement.java index 1075bf4dc882..bb07284a6f98 100644 --- a/plugins/generate-tostring/src/org/jetbrains/java/generate/element/FieldElement.java +++ b/plugins/generate-tostring/src/org/jetbrains/java/generate/element/FieldElement.java @@ -30,9 +30,10 @@ public class FieldElement extends AbstractElement implements Element { private boolean isModifierTransient; private boolean isModifierVolatile; + private String accessor; - public String getAccessor() { - return name; + public String getAccessor() { + return accessor; } /** @@ -103,4 +104,8 @@ public class FieldElement extends AbstractElement implements Element { ", isModifierVolatile=" + isModifierVolatile + "}"; } + + public void setAccessor(String accessor) { + this.accessor = accessor; + } } \ No newline at end of file