1 /*******************************************************************************
2 * Copyright (c) 2005, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 * Mateusz Matela <mateusz.matela@gmail.com> - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070
11 *******************************************************************************/
12 package org.eclipse.jdt.ui.actions;
14 import java.util.ArrayList;
15 import java.util.List;
17 import org.eclipse.swt.widgets.Shell;
19 import org.eclipse.core.resources.IWorkspaceRunnable;
21 import org.eclipse.ui.IWorkbenchSite;
22 import org.eclipse.ui.PlatformUI;
24 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
26 import org.eclipse.jdt.core.IJavaElement;
27 import org.eclipse.jdt.core.IType;
28 import org.eclipse.jdt.core.JavaModelException;
29 import org.eclipse.jdt.core.dom.IMethodBinding;
30 import org.eclipse.jdt.core.dom.ITypeBinding;
31 import org.eclipse.jdt.core.dom.IVariableBinding;
32 import org.eclipse.jdt.core.dom.Modifier;
34 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
35 import org.eclipse.jdt.internal.corext.dom.TypeRules;
36 import org.eclipse.jdt.internal.corext.util.Messages;
38 import org.eclipse.jdt.ui.JavaElementLabels;
40 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
41 import org.eclipse.jdt.internal.ui.actions.ActionMessages;
42 import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
43 import org.eclipse.jdt.internal.ui.dialogs.GenerateHashCodeEqualsDialog;
44 import org.eclipse.jdt.internal.ui.dialogs.SourceActionDialog;
45 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
46 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
47 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
50 * Adds method implementations for
51 * <code>{@link java.lang.Object#equals(java.lang.Object)}</code> and
52 * <code>{@link java.lang.Object#hashCode()}</code>. The action opens a
53 * dialog from which the user can choose the fields to be considered.
55 * Will open the parent compilation unit in a Java editor. The result is
56 * unsaved, so the user can decide if the changes are acceptable.
58 * The action is applicable to structured selections containing elements of type
59 * {@link org.eclipse.jdt.core.IType}.
62 * This class may be instantiated; it is not intended to be subclassed.
67 public final class GenerateHashCodeEqualsAction extends GenerateMethodAbstractAction {
69 private static final String METHODNAME_HASH_CODE= "hashCode"; //$NON-NLS-1$
70 private static final String METHODNAME_EQUALS= "equals"; //$NON-NLS-1$
72 class HashCodeEqualsInfo {
74 public boolean foundHashCode= false;
76 public boolean foundEquals= false;
78 public boolean foundFinalHashCode= false;
80 public boolean foundFinalEquals= false;
82 public boolean generated_8234583287028128664(GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
83 return (foundEquals || foundHashCode);
86 public HashCodeEqualsInfo generated_41324388328954759(ITypeBinding someType, boolean checkSuperclasses, GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
88 IMethodBinding[] declaredMethods= someType.getDeclaredMethods();
90 for (int i= 0; i < declaredMethods.length; i++) {
91 if (declaredMethods[i].getName().equals(GenerateHashCodeEqualsAction.METHODNAME_EQUALS)) {
92 ITypeBinding[] b= declaredMethods[i].getParameterTypes();
93 if ((b.length == 1) && (b[0].getQualifiedName().equals("java.lang.Object"))) { //$NON-NLS-1$
95 if (Modifier.isFinal(declaredMethods[i].getModifiers()))
96 foundFinalEquals= true;
99 if (declaredMethods[i].getName().equals(GenerateHashCodeEqualsAction.METHODNAME_HASH_CODE) && declaredMethods[i].getParameterTypes().length == 0) {
101 if (Modifier.isFinal(declaredMethods[i].getModifiers()))
102 foundFinalHashCode= true;
104 if (foundEquals && foundHashCode)
107 if (checkSuperclasses) {
108 someType= someType.getSuperclass();
109 if (someType == null || TypeRules.isJavaLangObject(someType)) {
120 public String generated_4859128944466735941(GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
121 String concreteHCEWarning= null;
123 if (!foundEquals && (!foundHashCode))
124 concreteHCEWarning= ActionMessages.GenerateHashCodeEqualsAction_equals_and_hashCode;
125 else if (!foundEquals)
126 concreteHCEWarning= ActionMessages.GenerateHashCodeEqualsAction_equals;
127 else if (!foundHashCode)
128 concreteHCEWarning= ActionMessages.GenerateHashCodeEqualsAction_hashCode;
129 return concreteHCEWarning;
133 public class HashCodeEqualsGenerationSettings extends CodeGenerationSettings {
134 public boolean useInstanceOf= false;
135 public boolean useBlocks= false;
136 public CodeGenerationSettings generated_851291004322909458(SourceActionDialog dialog, GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
137 GenerateHashCodeEqualsDialog generateHashCodeEqualsDialog= (GenerateHashCodeEqualsDialog)dialog;
138 useInstanceOf= generateHashCodeEqualsDialog.isUseInstanceOf();
139 useBlocks= generateHashCodeEqualsDialog.isUseBlocks();
144 private List<IVariableBinding> allFields;
145 private List<IVariableBinding> selectedFields;
147 private ArrayList<ITypeBinding> alreadyCheckedMemberTypes;
150 * Note: This constructor is for internal use only. Clients should not call
153 * @param editor the compilation unit editor
155 * @noreference This constructor is not intended to be referenced by clients.
157 public GenerateHashCodeEqualsAction(final CompilationUnitEditor editor) {
158 this(editor.getEditorSite());
160 setEnabled( (fEditor != null && SelectionConverter.canOperateOn(fEditor)));
164 * Creates a new generate hashCode equals action.
166 * The action requires that the selection provided by the site's selection
167 * provider is of type
168 * {@link org.eclipse.jface.viewers.IStructuredSelection}.
170 * @param site the workbench site providing context information for this
173 public GenerateHashCodeEqualsAction(final IWorkbenchSite site) {
175 setText(ActionMessages.GenerateHashCodeEqualsAction_label);
176 setDescription(ActionMessages.GenerateHashCodeEqualsAction_description);
177 setToolTipText(ActionMessages.GenerateHashCodeEqualsAction_tooltip);
178 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.GENERATE_HASHCODE_EQUALS_ACTION);
182 boolean isMethodAlreadyImplemented(ITypeBinding typeBinding) {
183 HashCodeEqualsInfo info= getTypeInfo(typeBinding, false);
184 return info.generated_8234583287028128664(this);
187 private HashCodeEqualsInfo getTypeInfo(ITypeBinding someType, boolean checkSuperclasses) {
188 HashCodeEqualsInfo info= new HashCodeEqualsInfo();
189 if (someType.isTypeVariable()) {
190 someType= someType.getErasure();
193 return info.generated_41324388328954759(someType, checkSuperclasses, this);
196 private RefactoringStatus checkHashCodeEqualsExists(ITypeBinding someType, boolean superClass) {
198 RefactoringStatus status= new RefactoringStatus();
199 HashCodeEqualsInfo info= getTypeInfo(someType, true);
201 String concreteTypeWarning= superClass ? ActionMessages.GenerateMethodAbstractAction_super_class : ActionMessages.GenerateHashCodeEqualsAction_field_type;
202 String concreteMethWarning= (someType.isInterface() || Modifier.isAbstract(someType.getModifiers()))
203 ? ActionMessages.GenerateHashCodeEqualsAction_interface_does_not_declare_hashCode_equals_error
204 : ActionMessages.GenerateHashCodeEqualsAction_type_does_not_implement_hashCode_equals_error;
205 String concreteHCEWarning= info.generated_4859128944466735941(this);
207 if (!info.foundEquals || !info.foundHashCode)
208 status.addWarning(Messages.format(concreteMethWarning, new String[] {
209 Messages.format(concreteTypeWarning, BindingLabelProvider.getBindingLabel(someType, JavaElementLabels.ALL_FULLY_QUALIFIED)), concreteHCEWarning }),
210 createRefactoringStatusContext(someType.getJavaElement()));
212 if (superClass && (info.foundFinalEquals || info.foundFinalHashCode)) {
213 status.addError(Messages.format(ActionMessages.GenerateMethodAbstractAction_final_method_in_superclass_error, new String[] {
214 Messages.format(concreteTypeWarning, BasicElementLabels.getJavaElementName(someType.getQualifiedName())), ActionMessages.GenerateHashCodeEqualsAction_hashcode_or_equals }),
215 createRefactoringStatusContext(someType.getJavaElement()));
222 CodeGenerationSettings createSettings(IType type, SourceActionDialog dialog) {
223 HashCodeEqualsGenerationSettings settings= new HashCodeEqualsGenerationSettings();
224 super.createSettings(type, dialog).setSettings(settings);
225 settings.createComments= dialog.getGenerateComment();
226 return settings.generated_851291004322909458(dialog, this);
230 void initialize(IType type) throws JavaModelException {
231 super.initialize(type);
232 alreadyCheckedMemberTypes= new ArrayList<ITypeBinding>();
236 String getAlreadyImplementedErrorMethodName() {
237 return ActionMessages.GenerateHashCodeEqualsAction_hashcode_or_equals;
241 boolean generateCandidates() {
242 IVariableBinding[] fCandidateFields= fTypeBinding.getDeclaredFields();
244 allFields= new ArrayList<IVariableBinding>();
245 selectedFields= new ArrayList<IVariableBinding>();
246 for (int i= 0; i < fCandidateFields.length; i++) {
247 if (!Modifier.isStatic(fCandidateFields[i].getModifiers())) {
248 allFields.add(fCandidateFields[i]);
249 if (!Modifier.isTransient(fCandidateFields[i].getModifiers()))
250 selectedFields.add(fCandidateFields[i]);
253 if (allFields.isEmpty()) {
260 SourceActionDialog createDialog(Shell shell, IType type) throws JavaModelException {
261 IVariableBinding[] allFieldBindings= allFields.toArray(new IVariableBinding[0]);
262 IVariableBinding[] selectedFieldBindings= selectedFields.toArray(new IVariableBinding[0]);
263 return new GenerateHashCodeEqualsDialog(shell, fEditor, type, allFieldBindings, selectedFieldBindings);
267 RefactoringStatus checkSuperClass(ITypeBinding superclass) {
268 return checkHashCodeEqualsExists(superclass, true);
272 RefactoringStatus checkGeneralConditions(IType type, CodeGenerationSettings settings, Object[] selected) {
273 return new RefactoringStatus();
277 RefactoringStatus checkMember(Object memberBinding) {
278 RefactoringStatus status= new RefactoringStatus();
279 IVariableBinding variableBinding= (IVariableBinding)memberBinding;
280 ITypeBinding fieldsType= variableBinding.getType();
281 if (fieldsType.isArray())
282 fieldsType= fieldsType.getElementType();
283 if (!fieldsType.isPrimitive() && !fieldsType.isEnum() && !alreadyCheckedMemberTypes.contains(fieldsType) && !fieldsType.equals(fTypeBinding)) {
284 status.merge(checkHashCodeEqualsExists(fieldsType, false));
285 alreadyCheckedMemberTypes.add(fieldsType);
287 if (Modifier.isTransient(variableBinding.getModifiers()))
288 status.addWarning(Messages.format(ActionMessages.GenerateHashCodeEqualsAction_transient_field_included_error, BasicElementLabels.getJavaElementName(variableBinding.getName())),
289 createRefactoringStatusContext(variableBinding.getJavaElement()));
294 IWorkspaceRunnable createOperation(Object[] selectedBindings, CodeGenerationSettings settings, boolean regenerate, IJavaElement type, IJavaElement elementPosition) {
295 return settings.generated_2154777900582332683(selectedBindings, this, regenerate, elementPosition);
299 String getErrorCaption() {
300 return ActionMessages.GenerateHashCodeEqualsAction_error_caption;
304 String getNoMembersError() {
305 return ActionMessages.GenerateHashCodeEqualsAction_no_nonstatic_fields_error;