KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > correction > ChangeMethodSignatureProposal


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.ui.text.correction;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.core.runtime.Assert;
19 import org.eclipse.core.runtime.CoreException;
20
21 import org.eclipse.swt.graphics.Image;
22
23 import org.eclipse.jdt.core.ICompilationUnit;
24 import org.eclipse.jdt.core.dom.AST;
25 import org.eclipse.jdt.core.dom.ASTNode;
26 import org.eclipse.jdt.core.dom.CompilationUnit;
27 import org.eclipse.jdt.core.dom.IBinding;
28 import org.eclipse.jdt.core.dom.IMethodBinding;
29 import org.eclipse.jdt.core.dom.ITypeBinding;
30 import org.eclipse.jdt.core.dom.IVariableBinding;
31 import org.eclipse.jdt.core.dom.Javadoc;
32 import org.eclipse.jdt.core.dom.MethodDeclaration;
33 import org.eclipse.jdt.core.dom.Name;
34 import org.eclipse.jdt.core.dom.SimpleName;
35 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
36 import org.eclipse.jdt.core.dom.TagElement;
37 import org.eclipse.jdt.core.dom.TextElement;
38 import org.eclipse.jdt.core.dom.Type;
39 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
40 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
41 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
42
43 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
44 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
45 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
46 import org.eclipse.jdt.internal.corext.dom.Bindings;
47 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
48 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
49
50 public class ChangeMethodSignatureProposal extends LinkedCorrectionProposal {
51
52     public static interface ChangeDescription {
53     }
54
55     public static class SwapDescription implements ChangeDescription {
56         final int index;
57         public SwapDescription(int index) {
58             this.index= index;
59         }
60     }
61
62     public static class RemoveDescription implements ChangeDescription {
63     }
64
65     static class ModifyDescription implements ChangeDescription {
66         public final String JavaDoc name;
67         public final ITypeBinding type;
68         Type resultingParamType;
69         SimpleName[] resultingParamName;
70         SimpleName resultingTagArg;
71
72         private ModifyDescription(ITypeBinding type, String JavaDoc name) {
73             this.type= type;
74             this.name= name;
75         }
76     }
77
78     public static class EditDescription extends ModifyDescription {
79         String JavaDoc orginalName;
80
81         public EditDescription(ITypeBinding type, String JavaDoc name) {
82             super(type, name);
83         }
84     }
85
86     public static class InsertDescription extends ModifyDescription {
87         public InsertDescription(ITypeBinding type, String JavaDoc name) {
88             super(type, name);
89         }
90     }
91
92     private ASTNode fInvocationNode;
93     private IMethodBinding fSenderBinding;
94     private ChangeDescription[] fParameterChanges;
95     private ChangeDescription[] fExceptionChanges;
96
97     public ChangeMethodSignatureProposal(String JavaDoc label, ICompilationUnit targetCU, ASTNode invocationNode, IMethodBinding binding, ChangeDescription[] paramChanges, ChangeDescription[] exceptionChanges, int relevance, Image image) {
98         super(label, targetCU, null, relevance, image);
99
100         Assert.isTrue(binding != null && Bindings.isDeclarationBinding(binding));
101
102         fInvocationNode= invocationNode;
103         fSenderBinding= binding;
104         fParameterChanges= paramChanges;
105         fExceptionChanges= exceptionChanges;
106     }
107
108     protected ASTRewrite getRewrite() throws CoreException {
109         CompilationUnit astRoot= (CompilationUnit) fInvocationNode.getRoot();
110         ASTNode methodDecl= astRoot.findDeclaringNode(fSenderBinding);
111         ASTNode newMethodDecl= null;
112         boolean isInDifferentCU;
113         if (methodDecl != null) {
114             isInDifferentCU= false;
115             newMethodDecl= methodDecl;
116         } else {
117             isInDifferentCU= true;
118             astRoot= ASTResolving.createQuickFixAST(getCompilationUnit(), null);
119             newMethodDecl= astRoot.findDeclaringNode(fSenderBinding.getKey());
120         }
121         createImportRewrite(astRoot);
122         
123         if (newMethodDecl instanceof MethodDeclaration) {
124             MethodDeclaration decl= (MethodDeclaration) newMethodDecl;
125
126             ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST());
127             if (fParameterChanges != null) {
128                 modifyParameters(rewrite, decl, isInDifferentCU);
129             }
130             if (fExceptionChanges != null) {
131                 modifyExceptions(rewrite, decl);
132             }
133             return rewrite;
134         }
135         return null;
136     }
137
138     private void modifyParameters(ASTRewrite rewrite, MethodDeclaration methodDecl, boolean isInDifferentCU) throws CoreException {
139         AST ast= methodDecl.getAST();
140
141         ArrayList JavaDoc usedNames= new ArrayList JavaDoc();
142         boolean hasCreatedVariables= false;
143
144         IVariableBinding[] declaredFields= fSenderBinding.getDeclaringClass().getDeclaredFields();
145         for (int i= 0; i < declaredFields.length; i++) { // avoid to take parameter names that are equal to field names
146
usedNames.add(declaredFields[i].getName());
147         }
148
149         ImportRewrite imports= getImportRewrite();
150         ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.PARAMETERS_PROPERTY);
151
152         List JavaDoc parameters= methodDecl.parameters(); // old parameters
153
int k= 0; // index over the oldParameters
154

155         for (int i= 0; i < fParameterChanges.length; i++) {
156             ChangeDescription curr= fParameterChanges[i];
157
158             if (curr == null) {
159                 SingleVariableDeclaration oldParam= (SingleVariableDeclaration) parameters.get(k);
160                 usedNames.add(oldParam.getName().getIdentifier());
161                 k++;
162             } else if (curr instanceof InsertDescription) {
163                 InsertDescription desc= (InsertDescription) curr;
164                 SingleVariableDeclaration newNode= ast.newSingleVariableDeclaration();
165                 newNode.setType(imports.addImport(desc.type, ast));
166                 newNode.setName(ast.newSimpleName("x")); //$NON-NLS-1$
167

168                 // remember to set name later
169
desc.resultingParamName= new SimpleName[] {newNode.getName()};
170                 desc.resultingParamType= newNode.getType();
171                 hasCreatedVariables= true;
172
173                 listRewrite.insertAt(newNode, i, null);
174
175                 Javadoc javadoc= methodDecl.getJavadoc();
176                 if (javadoc != null) {
177                     TagElement newTagElement= ast.newTagElement();
178                     newTagElement.setTagName(TagElement.TAG_PARAM);
179                     SimpleName arg= ast.newSimpleName("x"); //$NON-NLS-1$
180
newTagElement.fragments().add(arg);
181                     insertTabStop(rewrite, newTagElement.fragments(), "param_tagcomment" + i); //$NON-NLS-1$
182
insertParamTag(rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY), parameters, k, newTagElement);
183                     desc.resultingTagArg= arg; // set the name later
184
} else {
185                     desc.resultingTagArg= null;
186                 }
187             } else if (curr instanceof RemoveDescription) {
188                 SingleVariableDeclaration decl= (SingleVariableDeclaration) parameters.get(k);
189
190                 listRewrite.remove(decl, null);
191                 k++;
192
193                 TagElement tagNode= findParamTag(methodDecl, decl);
194                 if (tagNode != null) {
195                     rewrite.remove(tagNode, null);
196                 }
197             } else if (curr instanceof EditDescription) {
198                 EditDescription desc= (EditDescription) curr;
199
200                 ITypeBinding newTypeBinding= desc.type;
201                 SingleVariableDeclaration decl= (SingleVariableDeclaration) parameters.get(k);
202                 
203                 if (k == parameters.size() - 1 && i == fParameterChanges.length - 1 && decl.isVarargs() && newTypeBinding.isArray()) {
204                     newTypeBinding= newTypeBinding.getElementType(); // stick with varargs if it was before
205
} else {
206                     rewrite.set(decl, SingleVariableDeclaration.VARARGS_PROPERTY, Boolean.FALSE, null);
207                 }
208                 
209                 Type newType= imports.addImport(newTypeBinding, ast);
210                 rewrite.replace(decl.getType(), newType, null);
211                 rewrite.set(decl, SingleVariableDeclaration.EXTRA_DIMENSIONS_PROPERTY, new Integer JavaDoc(0), null);
212                 
213                 IBinding binding= decl.getName().resolveBinding();
214                 if (binding != null) {
215                     SimpleName[] names= LinkedNodeFinder.findByBinding(decl.getRoot(), binding);
216                     SimpleName[] newNames= new SimpleName[names.length];
217                     for (int j= 0; j < names.length; j++) {
218                         SimpleName newName= ast.newSimpleName("x"); //$NON-NLS-1$ // name will be set later
219
newNames[j]= newName;
220                         rewrite.replace(names[j], newName, null);
221                         
222                     }
223                     desc.resultingParamName= newNames;
224                 } else {
225                     SimpleName newName= ast.newSimpleName("x"); //$NON-NLS-1$ // name will be set later
226
rewrite.replace(decl.getName(), newName, null);
227                     // remember to set name later
228
desc.resultingParamName= new SimpleName[] {newName};
229                 }
230
231                 desc.resultingParamType= newType;
232                 desc.orginalName= decl.getName().getIdentifier();
233                 hasCreatedVariables= true;
234
235                 k++;
236
237                 TagElement tagNode= findParamTag(methodDecl, decl);
238                 if (tagNode != null) {
239                     List JavaDoc fragments= tagNode.fragments();
240                     if (!fragments.isEmpty()) {
241                         SimpleName arg= ast.newSimpleName("x"); //$NON-NLS-1$
242
rewrite.replace((ASTNode) fragments.get(0), arg, null);
243                         desc.resultingTagArg= arg;
244                     }
245                 }
246
247             } else if (curr instanceof SwapDescription) {
248                 SingleVariableDeclaration decl1= (SingleVariableDeclaration) parameters.get(k);
249                 SingleVariableDeclaration decl2= (SingleVariableDeclaration) parameters.get(((SwapDescription) curr).index);
250
251                 rewrite.replace(decl1, rewrite.createCopyTarget(decl2), null);
252                 rewrite.replace(decl2, rewrite.createCopyTarget(decl1), null);
253
254                 usedNames.add(decl1.getName().getIdentifier());
255                 k++;
256
257                 TagElement tagNode1= findParamTag(methodDecl, decl1);
258                 TagElement tagNode2= findParamTag(methodDecl, decl2);
259                 if (tagNode1 != null && tagNode2 != null) {
260                     rewrite.replace(tagNode1, rewrite.createCopyTarget(tagNode2), null);
261                     rewrite.replace(tagNode2, rewrite.createCopyTarget(tagNode1), null);
262                 }
263             }
264         }
265         if (!hasCreatedVariables) {
266             return;
267         }
268
269         if (methodDecl.getBody() != null) {
270             // avoid take a name of a local variable inside
271
CompilationUnit root= (CompilationUnit) methodDecl.getRoot();
272             IBinding[] bindings= (new ScopeAnalyzer(root)).getDeclarationsAfter(methodDecl.getBody().getStartPosition(), ScopeAnalyzer.VARIABLES);
273             for (int i= 0; i < bindings.length; i++) {
274                 usedNames.add(bindings[i].getName());
275             }
276         }
277
278         fixupNames(rewrite, usedNames, methodDecl, isInDifferentCU);
279     }
280
281     private void fixupNames(ASTRewrite rewrite, ArrayList JavaDoc usedNames, MethodDeclaration methodDecl, boolean isInDifferentCU) {
282         AST ast= rewrite.getAST();
283         // set names for new parameters
284
for (int i= 0; i < fParameterChanges.length; i++) {
285             ChangeDescription curr= fParameterChanges[i];
286             if (curr instanceof ModifyDescription) {
287                 ModifyDescription desc= (ModifyDescription) curr;
288
289                 String JavaDoc typeKey= getParamTypeGroupId(i);
290                 String JavaDoc nameKey= getParamNameGroupId(i);
291
292                 // collect name suggestions
293
String JavaDoc favourite= null;
294                 String JavaDoc[] excludedNames= (String JavaDoc[]) usedNames.toArray(new String JavaDoc[usedNames.size()]);
295                 
296                 String JavaDoc suggestedName= desc.name;
297                 if (suggestedName != null) {
298                     favourite= StubUtility.suggestArgumentName(getCompilationUnit().getJavaProject(), suggestedName, excludedNames);
299                     addLinkedPositionProposal(nameKey, favourite, null);
300                 }
301                 
302                 if (desc instanceof EditDescription) {
303                     addLinkedPositionProposal(nameKey, ((EditDescription)desc).orginalName, null);
304                 }
305                 
306                 Type type= desc.resultingParamType;
307                 String JavaDoc[] suggestedNames= StubUtility.getArgumentNameSuggestions(getCompilationUnit().getJavaProject(), type, excludedNames);
308                 for (int k= 0; k < suggestedNames.length; k++) {
309                     addLinkedPositionProposal(nameKey, suggestedNames[k], null);
310                 }
311                 if (favourite == null) {
312                     favourite= suggestedNames[0];
313                 }
314                 usedNames.add(favourite);
315                 
316                 SimpleName[] names= desc.resultingParamName;
317                 for (int j= 0; j < names.length; j++) {
318                     names[j].setIdentifier(favourite);
319                     addLinkedPosition(rewrite.track(names[j]), false, nameKey);
320                 }
321                 
322                 addLinkedPosition(rewrite.track(desc.resultingParamType), true, typeKey);
323
324                 // collect type suggestions
325
ITypeBinding[] bindings= ASTResolving.getRelaxingTypes(ast, desc.type);
326                 for (int k= 0; k < bindings.length; k++) {
327                     addLinkedPositionProposal(typeKey, bindings[k]);
328                 }
329
330                 SimpleName tagArg= desc.resultingTagArg;
331                 if (tagArg != null) {
332                     tagArg.setIdentifier(favourite);
333                     addLinkedPosition(rewrite.track(tagArg), false, nameKey);
334                 }
335             }
336         }
337     }
338
339     private TagElement findParamTag(MethodDeclaration decl, SingleVariableDeclaration param) {
340         Javadoc javadoc= decl.getJavadoc();
341         if (javadoc != null) {
342             return JavadocTagsSubProcessor.findParamTag(javadoc, param.getName().getIdentifier());
343         }
344         return null;
345     }
346
347     private TagElement insertParamTag(ListRewrite tagRewriter, List JavaDoc parameters, int currentIndex, TagElement newTagElement) {
348         HashSet JavaDoc previousNames= new HashSet JavaDoc();
349         for (int n = 0; n < currentIndex; n++) {
350             SingleVariableDeclaration var= (SingleVariableDeclaration) parameters.get(n);
351             previousNames.add(var.getName().getIdentifier());
352         }
353
354         JavadocTagsSubProcessor.insertTag(tagRewriter, newTagElement, previousNames);
355         return newTagElement;
356     }
357
358     private void modifyExceptions(ASTRewrite rewrite, MethodDeclaration methodDecl) throws CoreException {
359         AST ast= methodDecl.getAST();
360
361         ImportRewrite imports= getImportRewrite();
362         ListRewrite listRewrite= rewrite.getListRewrite(methodDecl, MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY);
363
364         List JavaDoc exceptions= methodDecl.thrownExceptions(); // old exceptions
365
int k= 0; // index over the old exceptions
366

367         for (int i= 0; i < fExceptionChanges.length; i++) {
368             ChangeDescription curr= fExceptionChanges[i];
369
370             if (curr == null) {
371                 k++;
372             } else if (curr instanceof InsertDescription) {
373                 InsertDescription desc= (InsertDescription) curr;
374                 String JavaDoc type= imports.addImport(desc.type);
375                 ASTNode newNode= ASTNodeFactory.newName(ast, type);
376
377                 listRewrite.insertAt(newNode, i, null);
378
379                 String JavaDoc key= getExceptionTypeGroupId(i);
380                 addLinkedPosition(rewrite.track(newNode), false, key);
381
382                 Javadoc javadoc= methodDecl.getJavadoc();
383                 if (javadoc != null) {
384                     TagElement newTagElement= ast.newTagElement();
385                     newTagElement.setTagName(TagElement.TAG_THROWS);
386                     ASTNode newRef= ASTNodeFactory.newName(ast, type);
387                     newTagElement.fragments().add(newRef);
388                     insertTabStop(rewrite, newTagElement.fragments(), "throws_tagcomment" + i); //$NON-NLS-1$
389
insertThrowsTag(rewrite.getListRewrite(javadoc, Javadoc.TAGS_PROPERTY), exceptions, k, newTagElement);
390
391                     addLinkedPosition(rewrite.track(newRef), false, key);
392                 }
393
394             } else if (curr instanceof RemoveDescription) {
395                 Name node= (Name) exceptions.get(k);
396
397                 listRewrite.remove(node, null);
398                 k++;
399
400                 TagElement tagNode= findThrowsTag(methodDecl, node);
401                 if (tagNode != null) {
402                     rewrite.remove(tagNode, null);
403                 }
404             } else if (curr instanceof EditDescription) {
405                 EditDescription desc= (EditDescription) curr;
406
407                 Name oldNode= (Name) exceptions.get(k);
408
409                 String JavaDoc type= imports.addImport(desc.type);
410                 ASTNode newNode= ASTNodeFactory.newName(ast, type);
411
412                 listRewrite.replace(oldNode, newNode, null);
413                 String JavaDoc key= getExceptionTypeGroupId(i);
414                 addLinkedPosition(rewrite.track(newNode), false, key);
415
416                 k++;
417
418                 TagElement tagNode= findThrowsTag(methodDecl, oldNode);
419                 if (tagNode != null) {
420                     ASTNode newRef= ASTNodeFactory.newName(ast, type);
421                     rewrite.replace((ASTNode) tagNode.fragments().get(0), newRef, null);
422                     addLinkedPosition(rewrite.track(newRef), false, key);
423                 }
424
425             } else if (curr instanceof SwapDescription) {
426                 Name decl1= (Name) exceptions.get(k);
427                 Name decl2= (Name) exceptions.get(((SwapDescription) curr).index);
428
429                 rewrite.replace(decl1, rewrite.createCopyTarget(decl2), null);
430                 rewrite.replace(decl2, rewrite.createCopyTarget(decl1), null);
431
432                 k++;
433
434                 TagElement tagNode1= findThrowsTag(methodDecl, decl1);
435                 TagElement tagNode2= findThrowsTag(methodDecl, decl2);
436                 if (tagNode1 != null && tagNode2 != null) {
437                     rewrite.replace(tagNode1, rewrite.createCopyTarget(tagNode2), null);
438                     rewrite.replace(tagNode2, rewrite.createCopyTarget(tagNode1), null);
439                 }
440             }
441         }
442     }
443
444     private void insertTabStop(ASTRewrite rewriter, List JavaDoc fragments, String JavaDoc linkedName) {
445         TextElement textElement= rewriter.getAST().newTextElement();
446         textElement.setText(""); //$NON-NLS-1$
447
fragments.add(textElement);
448         addLinkedPosition(rewriter.track(textElement), false, linkedName);
449     }
450
451     private TagElement findThrowsTag(MethodDeclaration decl, Name exception) {
452         Javadoc javadoc= decl.getJavadoc();
453         if (javadoc != null) {
454             String JavaDoc name= ASTNodes.getSimpleNameIdentifier(exception);
455             return JavadocTagsSubProcessor.findThrowsTag(javadoc, name);
456         }
457         return null;
458     }
459
460     private TagElement insertThrowsTag(ListRewrite tagRewriter, List JavaDoc exceptions, int currentIndex, TagElement newTagElement) {
461         HashSet JavaDoc previousNames= new HashSet JavaDoc();
462         for (int n = 0; n < currentIndex; n++) {
463             Name curr= (Name) exceptions.get(n);
464             previousNames.add(ASTNodes.getSimpleNameIdentifier(curr));
465         }
466
467         JavadocTagsSubProcessor.insertTag(tagRewriter, newTagElement, previousNames);
468         return newTagElement;
469     }
470
471
472     public String JavaDoc getParamNameGroupId(int idx) {
473         return "param_name_" + idx; //$NON-NLS-1$
474
}
475
476     public String JavaDoc getParamTypeGroupId(int idx) {
477         return "param_type_" + idx; //$NON-NLS-1$
478
}
479
480     public String JavaDoc getExceptionTypeGroupId(int idx) {
481         return "exc_type_" + idx; //$NON-NLS-1$
482
}
483
484 }
485
Popular Tags