KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > fix > VariableDeclarationFix


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 package org.eclipse.jdt.internal.corext.fix;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18
19 import org.eclipse.text.edits.TextEditGroup;
20
21 import org.eclipse.core.runtime.CoreException;
22
23 import org.eclipse.jdt.core.dom.ASTNode;
24 import org.eclipse.jdt.core.dom.Assignment;
25 import org.eclipse.jdt.core.dom.Block;
26 import org.eclipse.jdt.core.dom.CompilationUnit;
27 import org.eclipse.jdt.core.dom.ConstructorInvocation;
28 import org.eclipse.jdt.core.dom.ExpressionStatement;
29 import org.eclipse.jdt.core.dom.FieldDeclaration;
30 import org.eclipse.jdt.core.dom.IBinding;
31 import org.eclipse.jdt.core.dom.IMethodBinding;
32 import org.eclipse.jdt.core.dom.ITypeBinding;
33 import org.eclipse.jdt.core.dom.IVariableBinding;
34 import org.eclipse.jdt.core.dom.MethodDeclaration;
35 import org.eclipse.jdt.core.dom.Modifier;
36 import org.eclipse.jdt.core.dom.SimpleName;
37 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
38 import org.eclipse.jdt.core.dom.Statement;
39 import org.eclipse.jdt.core.dom.TypeDeclaration;
40 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
41 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
42 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
43 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
44
45 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
46 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
47 import org.eclipse.jdt.internal.corext.dom.VariableDeclarationRewrite;
48 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
49
50 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
51
52 public class VariableDeclarationFix extends AbstractFix {
53     
54     private static class WrittenNamesFinder extends GenericVisitor {
55         
56         private final HashMap JavaDoc fResult;
57     
58         public WrittenNamesFinder(HashMap JavaDoc result) {
59             fResult= result;
60         }
61         
62         /**
63          * {@inheritDoc}
64          */

65         public boolean visit(SimpleName node) {
66             if (node.getParent() instanceof VariableDeclarationFragment)
67                 return super.visit(node);
68             if (node.getParent() instanceof SingleVariableDeclaration)
69                 return super.visit(node);
70
71             IBinding binding= node.resolveBinding();
72             if (!(binding instanceof IVariableBinding))
73                 return super.visit(node);
74             
75             binding= ((IVariableBinding)binding).getVariableDeclaration();
76             if (ASTResolving.isWriteAccess(node)) {
77                 List JavaDoc list;
78                 if (fResult.containsKey(binding)) {
79                     list= (List JavaDoc)fResult.get(binding);
80                 } else {
81                     list= new ArrayList JavaDoc();
82                 }
83                 list.add(node);
84                 fResult.put(binding, list);
85             }
86             
87             return super.visit(node);
88         }
89     }
90
91     private static class VariableDeclarationFinder extends GenericVisitor {
92         
93         private final CompilationUnit fCompilationUnit;
94         private final List JavaDoc fResult;
95         private final HashMap JavaDoc fWrittenVariables;
96         private final boolean fAddFinalFields;
97         private final boolean fAddFinalParameters;
98         private final boolean fAddFinalLocals;
99         
100         public VariableDeclarationFinder(boolean addFinalFields,
101                 boolean addFinalParameters,
102                 boolean addFinalLocals,
103                 final CompilationUnit compilationUnit, final List JavaDoc result, final HashMap JavaDoc writtenNames) {
104             
105             super();
106             fAddFinalFields= addFinalFields;
107             fAddFinalParameters= addFinalParameters;
108             fAddFinalLocals= addFinalLocals;
109             fCompilationUnit= compilationUnit;
110             fResult= result;
111             fWrittenVariables= writtenNames;
112         }
113
114         /**
115          * {@inheritDoc}
116          */

117         public boolean visit(FieldDeclaration node) {
118             if (fAddFinalFields)
119                 return handleFragments(node.fragments(), node);
120             
121             return false;
122         }
123         
124         /**
125          * {@inheritDoc}
126          */

127         public boolean visit(VariableDeclarationStatement node) {
128             if (fAddFinalLocals)
129                 return handleFragments(node.fragments(), node);
130             
131             return false;
132         }
133
134         /**
135          * {@inheritDoc}
136          */

137         public boolean visit(VariableDeclarationExpression node) {
138             if (fAddFinalLocals && node.fragments().size() == 1) {
139                 SimpleName name= ((VariableDeclarationFragment)node.fragments().get(0)).getName();
140                 
141                 IBinding binding= name.resolveBinding();
142                 if (binding == null)
143                     return false;
144                 
145                 if (fWrittenVariables.containsKey(binding))
146                     return false;
147                 
148                 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node);
149                 if (op == null)
150                     return false;
151                 
152                 fResult.add(op);
153                 return false;
154             }
155             return false;
156         }
157         
158         private boolean handleFragments(List JavaDoc list, ASTNode declaration) {
159             List JavaDoc toChange= new ArrayList JavaDoc();
160             
161             for (Iterator JavaDoc iter= list.iterator(); iter.hasNext();) {
162                 VariableDeclarationFragment fragment= (VariableDeclarationFragment)iter.next();
163                 SimpleName name= fragment.getName();
164                 IBinding resolveBinding= name.resolveBinding();
165                 if (canAddFinal(resolveBinding, name, declaration)) {
166                     IVariableBinding varbinding= (IVariableBinding)resolveBinding;
167                     if (varbinding.isField()) {
168                         if (fieldCanBeFinal(fragment, varbinding))
169                             toChange.add(fragment);
170                     } else {
171                         if (!fWrittenVariables.containsKey(resolveBinding))
172                             toChange.add(fragment);
173                     }
174                 }
175             }
176             
177             if (toChange.size() == 0)
178                 return false;
179             
180             ModifierChangeOperation op= new ModifierChangeOperation(declaration, toChange, Modifier.FINAL, Modifier.VOLATILE);
181             fResult.add(op);
182             return false;
183         }
184         
185         private boolean fieldCanBeFinal(VariableDeclarationFragment fragment, IVariableBinding binding) {
186             if (Modifier.isStatic(((FieldDeclaration)fragment.getParent()).getModifiers()))
187                 return false;
188
189             if (!fWrittenVariables.containsKey(binding)) {
190                 //variable is not written
191
if (fragment.getInitializer() == null) {//variable is not initialized
192
return false;
193                 } else {
194                     return true;
195                 }
196             }
197             
198             if (fragment.getInitializer() != null)//variable is initialized and written
199
return false;
200             
201             ITypeBinding declaringClass= binding.getDeclaringClass();
202             if (declaringClass == null)
203                 return false;
204             
205             ArrayList JavaDoc writes= (ArrayList JavaDoc)fWrittenVariables.get(binding);
206             if (!isWrittenInTypeConstructors(binding, writes, declaringClass))
207                 return false;
208                 
209             HashSet JavaDoc writingConstructorBindings= new HashSet JavaDoc();
210             ArrayList JavaDoc writingConstructors= new ArrayList JavaDoc();
211             for (int i= 0; i < writes.size(); i++) {
212                 SimpleName name= (SimpleName)writes.get(i);
213                 MethodDeclaration constructor= getWritingConstructor(name);
214                 if (writingConstructors.contains(constructor))//variable is written twice or more in constructor
215
return false;
216                 
217                 writingConstructors.add(constructor);
218                 IMethodBinding constructorBinding= constructor.resolveBinding();
219                 if (constructorBinding == null)
220                     return false;
221                 
222                 writingConstructorBindings.add(constructorBinding);
223             }
224             
225             for (int i= 0; i < writingConstructors.size(); i++) {
226                 MethodDeclaration constructor= (MethodDeclaration)writingConstructors.get(i);
227                 if (callsWrittingConstructor(constructor, writingConstructorBindings))//writing constructor calls other writing constructor
228
return false;
229             }
230             
231             MethodDeclaration constructor= (MethodDeclaration)writingConstructors.get(0);
232             TypeDeclaration typeDecl= (TypeDeclaration)ASTNodes.getParent(constructor, TypeDeclaration.class);
233             if (typeDecl == null)
234                 return false;
235             
236             MethodDeclaration[] methods= typeDecl.getMethods();
237             for (int i= 0; i < methods.length; i++) {
238                 if (methods[i].isConstructor()) {
239                     IMethodBinding methodBinding= methods[i].resolveBinding();
240                     if (methodBinding == null)
241                         return false;
242                     
243                     if (!writingConstructorBindings.contains(methodBinding)) {
244                         if (!callsWrittingConstructor(methods[i], writingConstructorBindings))//non writing constructor does not call a writing constructor
245
return false;
246                     }
247                 }
248             }
249             
250             return true;
251         }
252
253         private boolean callsWrittingConstructor(MethodDeclaration methodDeclaration, HashSet JavaDoc writingConstructorBindings) {
254             Block body= methodDeclaration.getBody();
255             if (body == null)
256                 return false;
257             
258             List JavaDoc statements= body.statements();
259             if (statements.size() == 0)
260                 return false;
261             
262             Statement statement= (Statement)statements.get(0);
263             if (!(statement instanceof ConstructorInvocation))
264                 return false;
265             
266             ConstructorInvocation invocation= (ConstructorInvocation)statement;
267             IMethodBinding constructorBinding= invocation.resolveConstructorBinding();
268             if (constructorBinding == null)
269                 return false;
270             
271             if (writingConstructorBindings.contains(constructorBinding)) {
272                 return true;
273             } else {
274                 ASTNode declaration= ASTNodes.findDeclaration(constructorBinding, methodDeclaration.getParent());
275                 if (!(declaration instanceof MethodDeclaration))
276                     return false;
277                 
278                 return callsWrittingConstructor((MethodDeclaration)declaration, writingConstructorBindings);
279             }
280         }
281
282         private boolean isWrittenInTypeConstructors(IVariableBinding binding, ArrayList JavaDoc writes, ITypeBinding declaringClass) {
283             
284             for (int i= 0; i < writes.size(); i++) {
285                 SimpleName name= (SimpleName)writes.get(i);
286                 
287                 MethodDeclaration methodDeclaration= getWritingConstructor(name);
288                 if (methodDeclaration == null)
289                     return false;
290                 
291                 if (!methodDeclaration.isConstructor())
292                     return false;
293                 
294                 IMethodBinding constructor= methodDeclaration.resolveBinding();
295                 if (constructor == null)
296                     return false;
297                 
298                 ITypeBinding declaringClass2= constructor.getDeclaringClass();
299                 if (!declaringClass.equals(declaringClass2))
300                     return false;
301             }
302             
303             return true;
304         }
305
306         private MethodDeclaration getWritingConstructor(SimpleName name) {
307             Assignment assignement= (Assignment)ASTNodes.getParent(name, Assignment.class);
308             if (assignement == null)
309                 return null;
310             
311             ASTNode expression= assignement.getParent();
312             if (!(expression instanceof ExpressionStatement))
313                 return null;
314             
315             ASTNode block= expression.getParent();
316             if (!(block instanceof Block))
317                 return null;
318             
319             ASTNode methodDeclaration= block.getParent();
320             if (!(methodDeclaration instanceof MethodDeclaration))
321                 return null;
322             
323             return (MethodDeclaration)methodDeclaration;
324         }
325
326         /**
327          * {@inheritDoc}
328          */

329         public boolean visit(VariableDeclarationFragment node) {
330             SimpleName name= node.getName();
331             
332             IBinding binding= name.resolveBinding();
333             if (binding == null)
334                 return false;
335             
336             if (fWrittenVariables.containsKey(binding))
337                 return false;
338             
339             ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node);
340             if (op == null)
341                 return false;
342             
343             fResult.add(op);
344             return false;
345         }
346         
347         /**
348          * {@inheritDoc}
349          */

350         public boolean visit(SingleVariableDeclaration node) {
351             SimpleName name= node.getName();
352
353             IBinding binding= name.resolveBinding();
354             if (!(binding instanceof IVariableBinding))
355                 return false;
356
357             IVariableBinding varBinding= (IVariableBinding)binding;
358             if (fWrittenVariables.containsKey(varBinding))
359                 return false;
360             
361             if (fAddFinalParameters && fAddFinalLocals) {
362                 
363                 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node);
364                 if (op == null)
365                     return false;
366                 
367                 fResult.add(op);
368                 return false;
369             } else if (fAddFinalParameters) {
370                 if (!varBinding.isParameter())
371                     return false;
372                     
373                 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node);
374                 if (op == null)
375                     return false;
376                 
377                 fResult.add(op);
378                 return false;
379             } else if (fAddFinalLocals) {
380                 if (varBinding.isParameter())
381                     return false;
382                 
383                 ModifierChangeOperation op= createAddFinalOperation(name, fCompilationUnit, node);
384                 if (op == null)
385                     return false;
386                 
387                 fResult.add(op);
388                 return false;
389             }
390             return false;
391         }
392     }
393     
394     private static class ModifierChangeOperation extends AbstractFixRewriteOperation {
395         
396         private final ASTNode fDeclaration;
397         private final List JavaDoc fToChange;
398         private final int fIncludedModifiers;
399         private final int fExcludedModifiers;
400
401         public ModifierChangeOperation(ASTNode declaration, List JavaDoc toChange, int includedModifiers, int excludedModifiers) {
402             fDeclaration= declaration;
403             fToChange= toChange;
404             fIncludedModifiers= includedModifiers;
405             fExcludedModifiers= excludedModifiers;
406         }
407         
408         /**
409          * {@inheritDoc}
410          */

411         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc textEditGroups) throws CoreException {
412             ASTRewrite rewrite= cuRewrite.getASTRewrite();
413             
414             TextEditGroup group= createTextEditGroup(FixMessages.VariableDeclarationFix_changeModifierOfUnknownToFinal_description);
415             textEditGroups.add(group);
416             
417             if (fDeclaration instanceof VariableDeclarationStatement) {
418                 VariableDeclarationFragment[] toChange= (VariableDeclarationFragment[])fToChange.toArray(new VariableDeclarationFragment[fToChange.size()]);
419                 VariableDeclarationRewrite.rewriteModifiers((VariableDeclarationStatement)fDeclaration, toChange, fIncludedModifiers, fExcludedModifiers, rewrite, group);
420             } else if (fDeclaration instanceof FieldDeclaration) {
421                 VariableDeclarationFragment[] toChange= (VariableDeclarationFragment[])fToChange.toArray(new VariableDeclarationFragment[fToChange.size()]);
422                 VariableDeclarationRewrite.rewriteModifiers((FieldDeclaration)fDeclaration, toChange, fIncludedModifiers, fExcludedModifiers, rewrite, group);
423             } else if (fDeclaration instanceof SingleVariableDeclaration) {
424                 VariableDeclarationRewrite.rewriteModifiers((SingleVariableDeclaration)fDeclaration, fIncludedModifiers, fExcludedModifiers, rewrite, group);
425             } else if (fDeclaration instanceof VariableDeclarationExpression) {
426                 VariableDeclarationRewrite.rewriteModifiers((VariableDeclarationExpression)fDeclaration, fIncludedModifiers, fExcludedModifiers, rewrite, group);
427             }
428         }
429     }
430     
431     public static IFix createChangeModifierToFinalFix(final CompilationUnit compilationUnit, ASTNode[] selectedNodes) {
432         HashMap JavaDoc writtenNames= new HashMap JavaDoc();
433         WrittenNamesFinder finder= new WrittenNamesFinder(writtenNames);
434         compilationUnit.accept(finder);
435         List JavaDoc ops= new ArrayList JavaDoc();
436         VariableDeclarationFinder visitor= new VariableDeclarationFinder(true, true, true, compilationUnit, ops, writtenNames);
437         if (selectedNodes.length == 1) {
438             if (selectedNodes[0] instanceof SimpleName) {
439                 selectedNodes[0]= selectedNodes[0].getParent();
440             }
441             selectedNodes[0].accept(visitor);
442         } else {
443             for (int i= 0; i < selectedNodes.length; i++) {
444                 ASTNode selectedNode= selectedNodes[i];
445                 selectedNode.accept(visitor);
446             }
447         }
448         if (ops.size() == 0)
449             return null;
450         
451         IFixRewriteOperation[] result= (IFixRewriteOperation[])ops.toArray(new IFixRewriteOperation[ops.size()]);
452         String JavaDoc label;
453         if (result.length == 1) {
454             label= FixMessages.VariableDeclarationFix_changeModifierOfUnknownToFinal_description;
455         } else {
456             label= FixMessages.VariableDeclarationFix_ChangeMidifiersToFinalWherPossible_description;
457         }
458         return new VariableDeclarationFix(label, compilationUnit, result);
459     }
460     
461     public static IFix createCleanUp(CompilationUnit compilationUnit,
462             boolean addFinalFields, boolean addFinalParameters, boolean addFinalLocals) {
463         
464         if (!addFinalFields && !addFinalParameters && !addFinalLocals)
465             return null;
466         
467         HashMap JavaDoc writtenNames= new HashMap JavaDoc();
468         WrittenNamesFinder finder= new WrittenNamesFinder(writtenNames);
469         compilationUnit.accept(finder);
470         
471         List JavaDoc operations= new ArrayList JavaDoc();
472         VariableDeclarationFinder visitor= new VariableDeclarationFinder(addFinalFields, addFinalParameters, addFinalLocals, compilationUnit, operations, writtenNames);
473         compilationUnit.accept(visitor);
474         
475         if (operations.isEmpty())
476             return null;
477             
478         return new VariableDeclarationFix(FixMessages.VariableDeclarationFix_add_final_change_name, compilationUnit, (IFixRewriteOperation[])operations.toArray(new IFixRewriteOperation[operations.size()]));
479     }
480     
481     private static ModifierChangeOperation createAddFinalOperation(SimpleName name, CompilationUnit compilationUnit, ASTNode decl) {
482         if (decl == null)
483             return null;
484         
485         IBinding binding= name.resolveBinding();
486         if (!canAddFinal(binding, name, decl))
487             return null;
488         
489         if (decl instanceof SingleVariableDeclaration) {
490             return new ModifierChangeOperation(decl, new ArrayList JavaDoc(), Modifier.FINAL, Modifier.VOLATILE);
491         } else if (decl instanceof VariableDeclarationExpression) {
492             return new ModifierChangeOperation(decl, new ArrayList JavaDoc(), Modifier.FINAL, Modifier.VOLATILE);
493         } else if (decl instanceof VariableDeclarationFragment){
494             VariableDeclarationFragment frag= (VariableDeclarationFragment)decl;
495             decl= decl.getParent();
496             if (decl instanceof FieldDeclaration || decl instanceof VariableDeclarationStatement) {
497                 List JavaDoc list= new ArrayList JavaDoc();
498                 list.add(frag);
499                 return new ModifierChangeOperation(decl, list, Modifier.FINAL, Modifier.VOLATILE);
500             } else if (decl instanceof VariableDeclarationExpression) {
501                 return new ModifierChangeOperation(decl, new ArrayList JavaDoc(), Modifier.FINAL, Modifier.VOLATILE);
502             }
503         }
504         
505         return null;
506     }
507
508     private static boolean canAddFinal(IBinding binding, SimpleName name, ASTNode declNode) {
509         if (!(binding instanceof IVariableBinding))
510             return false;
511
512         IVariableBinding varbinding= (IVariableBinding)binding;
513         if (Modifier.isFinal(varbinding.getModifiers()))
514             return false;
515         
516         ASTNode parent= ASTNodes.getParent(declNode, VariableDeclarationExpression.class);
517         if (parent != null && ((VariableDeclarationExpression)parent).fragments().size() > 1)
518             return false;
519         
520         if (varbinding.isField() && !Modifier.isPrivate(varbinding.getModifiers()))
521             return false;
522         
523         if (varbinding.isParameter()) {
524             ASTNode varDecl= declNode.getParent();
525             if (varDecl instanceof MethodDeclaration) {
526                 MethodDeclaration declaration= (MethodDeclaration)varDecl;
527                 if (declaration.getBody() == null)
528                     return false;
529             }
530         }
531         
532         return true;
533     }
534
535     protected VariableDeclarationFix(String JavaDoc name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) {
536         super(name, compilationUnit, fixRewriteOperations);
537     }
538
539 }
540
Popular Tags