]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/ui/org/eclipse/jdt/ui/actions/GenerateHashCodeEqualsAction.java
Some talks, mostly identical.
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / ui / actions / GenerateHashCodeEqualsAction.java
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
7  *
8  * Contributors:
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;
13
14 import java.util.ArrayList;
15 import java.util.List;
16
17 import org.eclipse.swt.widgets.Shell;
18
19 import org.eclipse.core.resources.IWorkspaceRunnable;
20
21 import org.eclipse.ui.IWorkbenchSite;
22 import org.eclipse.ui.PlatformUI;
23
24 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
25
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;
33
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;
37
38 import org.eclipse.jdt.ui.JavaElementLabels;
39
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;
48
49 /**
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.
54  * <p>
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.
57  * <p>
58  * The action is applicable to structured selections containing elements of type
59  * {@link org.eclipse.jdt.core.IType}.
60  *
61  * <p>
62  * This class may be instantiated; it is not intended to be subclassed.
63  * </p>
64  *
65  * @since 3.2
66  */
67 public final class GenerateHashCodeEqualsAction extends GenerateMethodAbstractAction {
68         
69         private static final String METHODNAME_HASH_CODE= "hashCode"; //$NON-NLS-1$
70         private static final String METHODNAME_EQUALS= "equals"; //$NON-NLS-1$
71
72         class HashCodeEqualsInfo {
73
74                 public boolean foundHashCode= false;
75
76                 public boolean foundEquals= false;
77
78                 public boolean foundFinalHashCode= false;
79
80                 public boolean foundFinalEquals= false;
81
82                 public boolean generated_8234583287028128664(GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
83                         return (foundEquals || foundHashCode);
84                 }
85
86                 public HashCodeEqualsInfo generated_41324388328954759(ITypeBinding someType, boolean checkSuperclasses, GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
87                         while (true) {
88                                 IMethodBinding[] declaredMethods= someType.getDeclaredMethods();
89                 
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$
94                                                         foundEquals= true;
95                                                         if (Modifier.isFinal(declaredMethods[i].getModifiers()))
96                                                                 foundFinalEquals= true;
97                                                 }
98                                         }
99                                         if (declaredMethods[i].getName().equals(GenerateHashCodeEqualsAction.METHODNAME_HASH_CODE) && declaredMethods[i].getParameterTypes().length == 0) {
100                                                 foundHashCode= true;
101                                                 if (Modifier.isFinal(declaredMethods[i].getModifiers()))
102                                                         foundFinalHashCode= true;
103                                         }
104                                         if (foundEquals && foundHashCode)
105                                                 break;
106                                 }
107                                 if (checkSuperclasses) {
108                                         someType= someType.getSuperclass();
109                                         if (someType == null || TypeRules.isJavaLangObject(someType)) {
110                                                 break;
111                                         }
112                                 } else {
113                                         break;
114                                 }
115                         }
116                         
117                         return this;
118                 }
119
120                 public String generated_4859128944466735941(GenerateHashCodeEqualsAction generatehashcodeequalsaction) {
121                         String concreteHCEWarning= null;
122                 
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;
130                 }
131         }
132
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();
140                         return this;
141                 }
142         }
143
144         private List<IVariableBinding> allFields;
145         private List<IVariableBinding> selectedFields;
146
147         private ArrayList<ITypeBinding> alreadyCheckedMemberTypes;
148
149         /**
150          * Note: This constructor is for internal use only. Clients should not call
151          * this constructor.
152          *
153          * @param editor the compilation unit editor
154          *
155          * @noreference This constructor is not intended to be referenced by clients.
156          */
157         public GenerateHashCodeEqualsAction(final CompilationUnitEditor editor) {
158                 this(editor.getEditorSite());
159                 fEditor= editor;
160                 setEnabled( (fEditor != null && SelectionConverter.canOperateOn(fEditor)));
161         }
162
163         /**
164          * Creates a new generate hashCode equals action.
165          * <p>
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}.
169          *
170          * @param site the workbench site providing context information for this
171          *            action
172          */
173         public GenerateHashCodeEqualsAction(final IWorkbenchSite site) {
174                 super(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);
179         }
180
181         @Override
182         boolean isMethodAlreadyImplemented(ITypeBinding typeBinding) {
183                 HashCodeEqualsInfo info= getTypeInfo(typeBinding, false);
184                 return info.generated_8234583287028128664(this);
185         }
186
187         private HashCodeEqualsInfo getTypeInfo(ITypeBinding someType, boolean checkSuperclasses) {
188                 HashCodeEqualsInfo info= new HashCodeEqualsInfo();
189                 if (someType.isTypeVariable()) {
190                         someType= someType.getErasure();
191                 }
192                 
193                 return info.generated_41324388328954759(someType, checkSuperclasses, this);
194         }
195
196         private RefactoringStatus checkHashCodeEqualsExists(ITypeBinding someType, boolean superClass) {
197
198                 RefactoringStatus status= new RefactoringStatus();
199                 HashCodeEqualsInfo info= getTypeInfo(someType, true);
200
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);
206
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()));
211
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()));
216                 }
217
218                 return status;
219         }
220
221         @Override
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);
227         }
228
229         @Override
230         void initialize(IType type) throws JavaModelException {
231                 super.initialize(type);
232                 alreadyCheckedMemberTypes= new ArrayList<ITypeBinding>();
233         }
234
235         @Override
236         String getAlreadyImplementedErrorMethodName() {
237                 return ActionMessages.GenerateHashCodeEqualsAction_hashcode_or_equals;
238         }
239
240         @Override
241         boolean generateCandidates() {
242                 IVariableBinding[] fCandidateFields= fTypeBinding.getDeclaredFields();
243
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]);
251                         }
252                 }
253                 if (allFields.isEmpty()) {
254                         return false;
255                 }
256                 return true;
257         }
258
259         @Override
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);
264         }
265
266         @Override
267         RefactoringStatus checkSuperClass(ITypeBinding superclass) {
268                 return checkHashCodeEqualsExists(superclass, true);
269         }
270
271         @Override
272         RefactoringStatus checkGeneralConditions(IType type, CodeGenerationSettings settings, Object[] selected) {
273                 return new RefactoringStatus();
274         }
275
276         @Override
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);
286                 }
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()));
290                 return status;
291         }
292
293         @Override
294         IWorkspaceRunnable createOperation(Object[] selectedBindings, CodeGenerationSettings settings, boolean regenerate, IJavaElement type, IJavaElement elementPosition) {
295                 return settings.generated_2154777900582332683(selectedBindings, this, regenerate, elementPosition);
296         }
297
298         @Override
299         String getErrorCaption() {
300                 return ActionMessages.GenerateHashCodeEqualsAction_error_caption;
301         }
302
303         @Override
304         String getNoMembersError() {
305                 return ActionMessages.GenerateHashCodeEqualsAction_no_nonstatic_fields_error;
306         }
307
308 }