KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > hints > AddParameterOrLocalFix


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.hints;
21
22 import com.sun.source.tree.AssignmentTree;
23 import com.sun.source.tree.BlockTree;
24 import com.sun.source.tree.ExpressionStatementTree;
25 import com.sun.source.tree.ExpressionTree;
26 import com.sun.source.tree.IdentifierTree;
27 import com.sun.source.tree.MethodTree;
28 import com.sun.source.tree.StatementTree;
29 import com.sun.source.tree.Tree;
30 import com.sun.source.tree.Tree.Kind;
31 import com.sun.source.tree.VariableTree;
32 import com.sun.source.util.TreePath;
33 import com.sun.source.util.TreePathScanner;
34 import java.io.IOException JavaDoc;
35 import java.util.Arrays JavaDoc;
36 import java.util.EnumSet JavaDoc;
37 import java.util.EnumSet JavaDoc;
38 import java.util.logging.Level JavaDoc;
39 import java.util.logging.Logger JavaDoc;
40 import javax.lang.model.element.Element;
41 import javax.lang.model.element.Modifier;
42 import javax.lang.model.element.Modifier;
43 import javax.lang.model.type.DeclaredType;
44 import javax.lang.model.type.TypeKind;
45 import javax.lang.model.type.TypeMirror;
46 import org.netbeans.api.java.source.CancellableTask;
47 import org.netbeans.api.java.source.CompilationInfo;
48 import org.netbeans.api.java.source.JavaSource;
49 import org.netbeans.api.java.source.JavaSource.Phase;
50 import org.netbeans.api.java.source.TreeMaker;
51 import org.netbeans.api.java.source.TypeMirrorHandle;
52 import org.netbeans.api.java.source.WorkingCopy;
53 import org.netbeans.spi.editor.hints.ChangeInfo;
54 import org.netbeans.spi.editor.hints.Fix;
55 import org.openide.filesystems.FileObject;
56
57 /**
58  *
59  * @author Jan Lahoda
60  */

61 public class AddParameterOrLocalFix implements Fix {
62     
63     private FileObject file;
64     private TypeMirrorHandle type;
65     private String JavaDoc name;
66     private boolean parameter;
67     
68     private int /*!!!Position*/ unresolvedVariable;
69     
70     public AddParameterOrLocalFix(CompilationInfo info,
71                                   TypeMirror type, String JavaDoc name,
72                                   boolean parameter,
73                                   int /*!!!Position*/ unresolvedVariable) {
74         this.file = info.getFileObject();
75         if (type.getKind() == TypeKind.NULL) {
76             type = info.getElements().getTypeElement("java.lang.Object").asType();
77         }
78         this.type = TypeMirrorHandle.create(type);
79         this.name = name;
80         this.parameter = parameter;
81         this.unresolvedVariable = unresolvedVariable;
82     }
83
84     public String JavaDoc getText() {
85         return parameter ? "Create parameter " + name : "Create local variable " + name;
86     }
87
88     public ChangeInfo implement() {
89         try {
90             //use the original cp-info so it is "sure" that the proposedType can be resolved:
91
JavaSource js = JavaSource.forFileObject(file);
92             
93             js.runModificationTask(new CancellableTask<WorkingCopy>() {
94                 public void cancel() {
95                 }
96                 public void run(final WorkingCopy working) throws IOException JavaDoc {
97                     working.toPhase(Phase.RESOLVED);
98                     
99                     TypeMirror proposedType = type.resolve(working);
100                     
101                     if (proposedType == null) {
102                         JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve proposed type.");
103                         return;
104                     }
105                     
106                     TreeMaker make = working.getTreeMaker();
107                     TreePath tp = working.getTreeUtilities().pathFor(unresolvedVariable + 1);
108                     
109                     assert tp.getLeaf().getKind() == Kind.IDENTIFIER;
110                     
111                     MethodTree targetTree = findMethod(tp);
112                     
113                     if (parameter) {
114                         if (targetTree == null) {
115                             Logger.getLogger("global").log(Level.WARNING, "Add parameter - cannot find the method.");
116                         }
117                         
118                         MethodTree result = make.addMethodParameter(targetTree, make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), name, make.Type(proposedType), null));
119                         
120                         working.rewrite(targetTree, result);
121                     } else {
122                         resolveLocalVariable(working, tp, make, proposedType);
123                     }
124                 }
125             }).commit();
126         } catch (IOException JavaDoc e) {
127             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
128         }
129         
130         return null;
131     }
132     
133     private void resolveLocalVariable(final WorkingCopy wc, TreePath tp, TreeMaker make, TypeMirror proposedType) {
134         final String JavaDoc name = ((IdentifierTree) tp.getLeaf()).getName().toString();
135         
136         final Element el = wc.getTrees().getElement(tp);
137         
138         //find first usage of this (undeclared) variable:
139
TreePath method = tp;
140         
141         while (method.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
142             if (method.getLeaf().getKind() == Kind.METHOD) {
143                 break;
144             }
145             
146             method = method.getParentPath();
147         }
148         
149         if (method.getLeaf().getKind() != Kind.METHOD) {
150             //TODO: probably initializer handle differently
151
return;
152         }
153         
154         class FirstUsage extends TreePathScanner<TreePath, Void JavaDoc> {
155             private TreePath found;
156             public @Override JavaDoc TreePath visitIdentifier(IdentifierTree tree, Void JavaDoc v) {
157                 if (tree.getName().contentEquals(el.getSimpleName())) {
158                     if (found == null) {
159                         found = getCurrentPath();
160                     }
161                     return findStatement(getCurrentPath());
162                 }
163                 return null;
164             }
165             public @Override JavaDoc TreePath visitBlock(BlockTree tree, Void JavaDoc v) {
166                 TreePath result = null;
167                 TreePath firstBranchStatementWithUsage = null;
168                 for (StatementTree t : tree.getStatements()) {
169                     TreePath currentResult = scan(t, null);
170                     
171                     if (currentResult != null && result == null) {
172                         result = currentResult;
173                         firstBranchStatementWithUsage = new TreePath(getCurrentPath(), t);
174                     }
175                     
176                     if (currentResult != t && result != null && result.getLeaf() != firstBranchStatementWithUsage.getLeaf()) {
177                         //ie.: { x = 1; } ... { x = 1; }
178
result = firstBranchStatementWithUsage;
179                     }
180                 }
181                 super.visitBlock(tree, v);
182                 return result;
183             }
184             public @Override JavaDoc TreePath reduce(TreePath tp1, TreePath tp2) {
185                 if (tp2 == null)
186                     return tp1;
187                 
188                 return tp2;
189                 
190             }
191         }
192         
193         FirstUsage firstUsage = new FirstUsage();
194         TreePath firstUse = firstUsage.scan(method, null);
195         
196         if (firstUse == null || !isStatement(firstUse.getLeaf())) {
197             Logger.getLogger("global").log(Level.WARNING, "Add local variable - cannot find a statement.");
198             return;
199         }
200         
201         StatementTree statement = (StatementTree) firstUse.getLeaf();
202         
203         if (statement.getKind() == Kind.EXPRESSION_STATEMENT) {
204             ExpressionTree exp = ((ExpressionStatementTree) statement).getExpression();
205             
206             if (exp.getKind() == Kind.ASSIGNMENT) {
207                 //replace the expression statement with a variable declaration:
208
AssignmentTree at = (AssignmentTree) exp;
209                 VariableTree vt = make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), name, make.Type(proposedType), at.getExpression());
210                 
211                 wc.rewrite(statement, vt);
212                 
213                 return;
214             }
215         }
216         
217         Tree statementParent = firstUse.getParentPath().getLeaf();
218         VariableTree vt = make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), name, make.Type(proposedType), null);
219         
220         if (statementParent.getKind() == Kind.BLOCK) {
221             BlockTree block = (BlockTree) statementParent;
222             BlockTree nueBlock = make.insertBlockStatement(block, block.getStatements().indexOf(statement), vt);
223             
224             wc.rewrite(block, nueBlock);
225         } else {
226             BlockTree block = make.Block(Arrays.asList(vt, statement), false);
227             
228             wc.rewrite(statement, block);
229         }
230     }
231     
232     private TreePath findStatement(TreePath tp) {
233         TreePath statement = tp;
234         
235         while (statement.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
236             if (isStatement(statement.getLeaf())) {
237                 return statement;
238             }
239             
240             statement = statement.getParentPath();
241         }
242         
243         return null;
244     }
245     
246     private MethodTree findMethod(TreePath tp) {
247         TreePath method = tp;
248         
249         while (method.getLeaf().getKind() != Kind.COMPILATION_UNIT) {
250             if (method.getLeaf().getKind() == Kind.METHOD) {
251                 return (MethodTree) method.getLeaf();
252             }
253             
254             method = method.getParentPath();
255         }
256         
257         return null;
258     }
259     
260     private boolean isStatement(Tree t) {
261         Class JavaDoc intClass = t.getKind().asInterface();
262         
263         return StatementTree.class.isAssignableFrom(intClass);
264     }
265     
266     String JavaDoc toDebugString(CompilationInfo info) {
267         return "AddParameterOrLocalFix:" + name + ":" + type.resolve(info).toString() + ":" + parameter;
268     }
269 }
270
Popular Tags