]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/text/correction/GetterSetterCorrectionSubProcessor.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / text / correction / GetterSetterCorrectionSubProcessor.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2007, 2012 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 *******************************************************************************/
11package org.eclipse.jdt.internal.ui.text.correction;
12
13import java.lang.reflect.InvocationTargetException;
14import java.util.ArrayList;
15import java.util.Collection;
16
17import org.eclipse.swt.graphics.Image;
18import org.eclipse.swt.widgets.Display;
19
20import org.eclipse.core.runtime.CoreException;
21import org.eclipse.core.runtime.IProgressMonitor;
22import org.eclipse.core.runtime.NullProgressMonitor;
23
24import org.eclipse.core.resources.IFile;
25
26import org.eclipse.jface.text.IDocument;
27
28import org.eclipse.ui.IWorkbenchWindow;
29import org.eclipse.ui.PlatformUI;
30
31import org.eclipse.ltk.core.refactoring.Change;
32import org.eclipse.ltk.core.refactoring.CompositeChange;
33import org.eclipse.ltk.core.refactoring.RefactoringStatus;
34import org.eclipse.ltk.core.refactoring.TextFileChange;
35
36import org.eclipse.jdt.core.Flags;
37import org.eclipse.jdt.core.ICompilationUnit;
38import org.eclipse.jdt.core.IField;
39import org.eclipse.jdt.core.IJavaElement;
40import org.eclipse.jdt.core.IJavaProject;
41import org.eclipse.jdt.core.JavaModelException;
42import org.eclipse.jdt.core.compiler.IProblem;
43import org.eclipse.jdt.core.dom.AST;
44import org.eclipse.jdt.core.dom.ASTNode;
45import org.eclipse.jdt.core.dom.Expression;
46import org.eclipse.jdt.core.dom.IBinding;
47import org.eclipse.jdt.core.dom.IMethodBinding;
48import org.eclipse.jdt.core.dom.ITypeBinding;
49import org.eclipse.jdt.core.dom.IVariableBinding;
50import org.eclipse.jdt.core.dom.MethodInvocation;
51import org.eclipse.jdt.core.dom.Modifier;
52import org.eclipse.jdt.core.dom.Name;
53import org.eclipse.jdt.core.dom.QualifiedName;
54import org.eclipse.jdt.core.dom.SimpleName;
55import org.eclipse.jdt.core.dom.SuperFieldAccess;
56import org.eclipse.jdt.core.dom.SuperMethodInvocation;
57import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
58
59import org.eclipse.jdt.internal.corext.codemanipulation.GetterSetterUtil;
60import org.eclipse.jdt.internal.corext.dom.ASTNodes;
61import org.eclipse.jdt.internal.corext.dom.Bindings;
62import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
63import org.eclipse.jdt.internal.corext.refactoring.sef.SelfEncapsulateFieldRefactoring;
64import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
65import org.eclipse.jdt.internal.corext.util.Messages;
66
67import org.eclipse.jdt.ui.refactoring.RefactoringSaveHelper;
68import org.eclipse.jdt.ui.text.java.IInvocationContext;
69import org.eclipse.jdt.ui.text.java.IProblemLocation;
70import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal;
71import org.eclipse.jdt.ui.text.java.correction.ChangeCorrectionProposal;
72import org.eclipse.jdt.ui.text.java.correction.ICommandAccess;
73
74import org.eclipse.jdt.internal.ui.JavaPlugin;
75import org.eclipse.jdt.internal.ui.JavaPluginImages;
76import org.eclipse.jdt.internal.ui.refactoring.RefactoringExecutionHelper;
77import org.eclipse.jdt.internal.ui.refactoring.actions.RefactoringStarter;
78import org.eclipse.jdt.internal.ui.refactoring.sef.SelfEncapsulateFieldWizard;
79import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
80import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
81
82
83public class GetterSetterCorrectionSubProcessor {
84
85 public static final String SELF_ENCAPSULATE_FIELD_ID= "org.eclipse.jdt.ui.correction.encapsulateField.assist"; //$NON-NLS-1$
86
87 private static class ProposalParameter {
88 public final boolean useSuper;
89 public final ICompilationUnit compilationUnit;
90 public final ASTRewrite astRewrite;
91 public final Expression accessNode;
92 public final Expression qualifier;
93 public final IVariableBinding variableBinding;
94
95 public ProposalParameter(boolean useSuper, ICompilationUnit compilationUnit, ASTRewrite rewrite, Expression accessNode, Expression qualifier, IVariableBinding variableBinding) {
96 this.useSuper= useSuper;
97 this.compilationUnit= compilationUnit;
98 this.astRewrite= rewrite;
99 this.accessNode= accessNode;
100 this.qualifier= qualifier;
101 this.variableBinding= variableBinding;
102 }
103 }
104
105 public static class SelfEncapsulateFieldProposal extends ChangeCorrectionProposal { // public for tests
106
107 private IField fField;
108 private boolean fNoDialog;
109
110 public SelfEncapsulateFieldProposal(int relevance, IField field) {
111 super(getDescription(field), null, relevance, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE));
112 fField= field;
113 fNoDialog= false;
114 setCommandId(SELF_ENCAPSULATE_FIELD_ID);
115 }
116
117 public IField getField() {
118 return fField;
119 }
120
121 public void setNoDialog(boolean noDialog) {
122 fNoDialog= noDialog;
123 }
124
125 public TextFileChange getChange(IFile file) throws CoreException {
126 final SelfEncapsulateFieldRefactoring refactoring= new SelfEncapsulateFieldRefactoring(fField);
127 refactoring.setVisibility(Flags.AccPublic);
128 refactoring.setConsiderVisibility(false);//private field references are just searched in local file
129 refactoring.checkInitialConditions(new NullProgressMonitor());
130 refactoring.checkFinalConditions(new NullProgressMonitor());
131 Change createdChange= refactoring.createChange(new NullProgressMonitor());
132 if (createdChange instanceof CompositeChange) {
133 Change[] children= ((CompositeChange) createdChange).getChildren();
134 for (int i= 0; i < children.length; i++) {
135 Change curr= children[i];
136 if (curr instanceof TextFileChange && ((TextFileChange) curr).getFile().equals(file)) {
137 return (TextFileChange) curr;
138 }
139 }
140 }
141 return null;
142 }
143
144
145 private static String getDescription(IField field) {
146 return Messages.format(CorrectionMessages.GetterSetterCorrectionSubProcessor_creategetterunsingencapsulatefield_description, BasicElementLabels.getJavaElementName(field.getElementName()));
147 }
148
149 /*
150 * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension5#getAdditionalProposalInfo(org.eclipse.core.runtime.IProgressMonitor)
151 * @since 3.5
152 */
153 @Override
154 public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
155 return CorrectionMessages.GetterSetterCorrectionSubProcessor_additional_info;
156 }
157
158 @Override
159 public void apply(IDocument document) {
160 try {
161 final SelfEncapsulateFieldRefactoring refactoring= new SelfEncapsulateFieldRefactoring(fField);
162 refactoring.setVisibility(Flags.AccPublic);
163 refactoring.setConsiderVisibility(false);//private field references are just searched in local file
164 if (fNoDialog) {
165 IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
166 final RefactoringExecutionHelper helper= new RefactoringExecutionHelper(refactoring, RefactoringStatus.ERROR, RefactoringSaveHelper.SAVE_REFACTORING, JavaPlugin.getActiveWorkbenchShell(), window);
167 if (Display.getCurrent() != null) {
168 try {
169 helper.perform(false, false);
170 } catch (InterruptedException e) {
171 JavaPlugin.log(e);
172 } catch (InvocationTargetException e) {
173 JavaPlugin.log(e);
174 }
175 } else {
176 Display.getDefault().syncExec(new Runnable() {
177 public void run() {
178 try {
179 helper.perform(false, false);
180 } catch (InterruptedException e) {
181 JavaPlugin.log(e);
182 } catch (InvocationTargetException e) {
183 JavaPlugin.log(e);
184 }
185 }
186 });
187 }
188 } else {
189 new RefactoringStarter().activate(new SelfEncapsulateFieldWizard(refactoring), JavaPlugin.getActiveWorkbenchShell(), "", RefactoringSaveHelper.SAVE_REFACTORING); //$NON-NLS-1$
190 }
191 } catch (JavaModelException e) {
192 ExceptionHandler.handle(e, CorrectionMessages.GetterSetterCorrectionSubProcessor_encapsulate_field_error_title, CorrectionMessages.GetterSetterCorrectionSubProcessor_encapsulate_field_error_message);
193 }
194 }
195 }
196
197 /**
198 * Used by quick assist
199 * @param context the invocation context
200 * @param coveringNode the covering node
201 * @param locations the problems at the corrent location
202 * @param resultingCollections the resulting proposals
203 * @return <code>true</code> if the quick assist is applicable at this offset
204 */
205 public static boolean addGetterSetterProposal(IInvocationContext context, ASTNode coveringNode, IProblemLocation[] locations, ArrayList<ICommandAccess> resultingCollections) {
206 if (locations != null) {
207 for (int i= 0; i < locations.length; i++) {
208 int problemId= locations[i].getProblemId();
209 if (problemId == IProblem.UnusedPrivateField)
210 return false;
211 if (problemId == IProblem.UnqualifiedFieldAccess)
212 return false;
213 }
214 }
215 return addGetterSetterProposal(context, coveringNode, resultingCollections, 7);
216 }
217
218 public static void addGetterSetterProposal(IInvocationContext context, IProblemLocation location, Collection<ICommandAccess> proposals, int relevance) {
219 addGetterSetterProposal(context, location.getCoveringNode(context.getASTRoot()), proposals, relevance);
220 }
221
222 private static boolean addGetterSetterProposal(IInvocationContext context, ASTNode coveringNode, Collection<ICommandAccess> proposals, int relevance) {
223 if (!(coveringNode instanceof SimpleName)) {
224 return false;
225 }
226 SimpleName sn= (SimpleName) coveringNode;
227
228 IBinding binding= sn.resolveBinding();
229 if (!(binding instanceof IVariableBinding))
230 return false;
231 IVariableBinding variableBinding= (IVariableBinding) binding;
232 if (!variableBinding.isField())
233 return false;
234
235 if (proposals == null)
236 return true;
237
238 ChangeCorrectionProposal proposal= getProposal(context.getCompilationUnit(), sn, variableBinding, relevance);
239 if (proposal != null)
240 proposals.add(proposal);
241 return true;
242 }
243
244 private static ChangeCorrectionProposal getProposal(ICompilationUnit cu, SimpleName sn, IVariableBinding variableBinding, int relevance) {
245 Expression accessNode= sn;
246 Expression qualifier= null;
247 boolean useSuper= false;
248
249 ASTNode parent= sn.getParent();
250 switch (parent.getNodeType()) {
251 case ASTNode.QUALIFIED_NAME:
252 accessNode= (Expression) parent;
253 qualifier= ((QualifiedName) parent).getQualifier();
254 break;
255 case ASTNode.SUPER_FIELD_ACCESS:
256 accessNode= (Expression) parent;
257 qualifier= ((SuperFieldAccess) parent).getQualifier();
258 useSuper= true;
259 break;
260 }
261 ASTRewrite rewrite= ASTRewrite.create(sn.getAST());
262 ProposalParameter gspc= new ProposalParameter(useSuper, cu, rewrite, accessNode, qualifier, variableBinding);
263 if (ASTResolving.isWriteAccess(sn))
264 return addSetterProposal(gspc, relevance);
265 else
266 return addGetterProposal(gspc, relevance);
267 }
268
269 /**
270 * Proposes a getter for this field.
271 *
272 * @param context the proposal parameter
273 * @param relevance relevance of this proposal
274 * @return the proposal if available or null
275 */
276 private static ChangeCorrectionProposal addGetterProposal(ProposalParameter context, int relevance) {
277 IMethodBinding method= findGetter(context);
278 if (method != null) {
279 Expression mi= createMethodInvocation(context, method, null);
280 context.astRewrite.replace(context.accessNode, mi, null);
281
282 String label= Messages.format(CorrectionMessages.GetterSetterCorrectionSubProcessor_replacewithgetter_description, BasicElementLabels.getJavaCodeString(ASTNodes.asString(context.accessNode)));
283 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
284 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.compilationUnit, context.astRewrite, relevance, image);
285 return proposal;
286 } else {
287 IJavaElement element= context.variableBinding.getJavaElement();
288 if (element instanceof IField) {
289 IField field= (IField) element;
290 try {
291 if (RefactoringAvailabilityTester.isSelfEncapsulateAvailable(field))
292 return new SelfEncapsulateFieldProposal(relevance, field);
293 } catch (JavaModelException e) {
294 JavaPlugin.log(e);
295 }
296 }
297 }
298 return null;
299 }
300
301 private static IMethodBinding findGetter(ProposalParameter context) {
302 ITypeBinding returnType= context.variableBinding.getType();
303 String getterName= GetterSetterUtil.getGetterName(context.variableBinding, context.compilationUnit.getJavaProject(), null, isBoolean(context));
304 ITypeBinding declaringType= context.variableBinding.getDeclaringClass();
305 if (declaringType == null)
306 return null;
307 IMethodBinding getter= Bindings.findMethodInHierarchy(declaringType, getterName, new ITypeBinding[0]);
308 if (getter != null && getter.getReturnType().isAssignmentCompatible(returnType) && Modifier.isStatic(getter.getModifiers()) == Modifier.isStatic(context.variableBinding.getModifiers()))
309 return getter;
310 return null;
311 }
312
313 private static Expression createMethodInvocation(ProposalParameter context, IMethodBinding method, Expression argument) {
314 AST ast= context.astRewrite.getAST();
315 Expression qualifier= context.qualifier;
316 if (context.useSuper) {
317 SuperMethodInvocation invocation= ast.newSuperMethodInvocation();
318 invocation.setName(ast.newSimpleName(method.getName()));
319 if (qualifier != null)
320 invocation.setQualifier((Name) context.astRewrite.createCopyTarget(qualifier));
321 if (argument != null)
322 invocation.arguments().add(argument);
323 return invocation;
324 } else {
325 MethodInvocation invocation= ast.newMethodInvocation();
326 invocation.setName(ast.newSimpleName(method.getName()));
327 if (qualifier != null)
328 invocation.setExpression((Expression) context.astRewrite.createCopyTarget(qualifier));
329 if (argument != null)
330 invocation.arguments().add(argument);
331 return invocation;
332 }
333 }
334
335 /**
336 * Proposes a setter for this field.
337 *
338 * @param context the proposal parameter
339 * @param relevance relevance of this proposal
340 * @return the proposal if available or null
341 */
342 private static ChangeCorrectionProposal addSetterProposal(ProposalParameter context, int relevance) {
343 boolean isBoolean= isBoolean(context);
344 String setterName= GetterSetterUtil.getSetterName(context.variableBinding, context.compilationUnit.getJavaProject(), null, isBoolean);
345 ITypeBinding declaringType= context.variableBinding.getDeclaringClass();
346 if (declaringType == null)
347 return null;
348
349 IMethodBinding method= Bindings.findMethodInHierarchy(declaringType, setterName, new ITypeBinding[] { context.variableBinding.getType() });
350 if (method != null && Bindings.isVoidType(method.getReturnType()) && (Modifier.isStatic(method.getModifiers()) == Modifier.isStatic(context.variableBinding.getModifiers()))) {
351 Expression assignedValue= getAssignedValue(context);
352 if (assignedValue == null)
353 return null; //we don't know how to handle those cases.
354 Expression mi= createMethodInvocation(context, method, assignedValue);
355 context.astRewrite.replace(context.accessNode.getParent(), mi, null);
356
357 String label= Messages.format(CorrectionMessages.GetterSetterCorrectionSubProcessor_replacewithsetter_description, BasicElementLabels.getJavaCodeString(ASTNodes.asString(context.accessNode)));
358 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
359 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.compilationUnit, context.astRewrite, relevance, image);
360 return proposal;
361 } else {
362 IJavaElement element= context.variableBinding.getJavaElement();
363 if (element instanceof IField) {
364 IField field= (IField) element;
365 try {
366 if (RefactoringAvailabilityTester.isSelfEncapsulateAvailable(field))
367 return new SelfEncapsulateFieldProposal(relevance, field);
368 } catch (JavaModelException e) {
369 JavaPlugin.log(e);
370 }
371 }
372 }
373 return null;
374 }
375
376 private static boolean isBoolean(ProposalParameter context) {
377 AST ast= context.astRewrite.getAST();
378 boolean isBoolean= ast.resolveWellKnownType("boolean") == context.variableBinding.getType(); //$NON-NLS-1$
379 if (!isBoolean)
380 isBoolean= ast.resolveWellKnownType("java.lang.Boolean") == context.variableBinding.getType(); //$NON-NLS-1$
381 return isBoolean;
382 }
383
384 private static Expression getAssignedValue(ProposalParameter context) {
385 ASTNode parent= context.accessNode.getParent();
386 ASTRewrite astRewrite= context.astRewrite;
387 IJavaProject javaProject= context.compilationUnit.getJavaProject();
388 IMethodBinding getter= findGetter(context);
389 Expression getterExpression= null;
390 if (getter != null) {
391 getterExpression= astRewrite.getAST().newSimpleName("placeholder"); //$NON-NLS-1$
392 }
393 ITypeBinding type= context.variableBinding.getType();
394 boolean is50OrHigher= JavaModelUtil.is50OrHigher(javaProject);
395 Expression result= GetterSetterUtil.getAssignedValue(parent, astRewrite, getterExpression, type, is50OrHigher);
396 if (result != null && getterExpression != null && getterExpression.getParent() != null) {
397 getterExpression.getParent().setStructuralProperty(getterExpression.getLocationInParent(), createMethodInvocation(context, getter, null));
398 }
399 return result;
400 }
401
402}