Lines 41-101
Link Here
|
41 |
* Version 2 license, then the option applies only if the new code is |
41 |
* Version 2 license, then the option applies only if the new code is |
42 |
* made subject to such option by the copyright holder. |
42 |
* made subject to such option by the copyright holder. |
43 |
*/ |
43 |
*/ |
44 |
|
|
|
45 |
package org.netbeans.modules.refactoring.java.plugins; |
44 |
package org.netbeans.modules.refactoring.java.plugins; |
46 |
|
45 |
|
47 |
import com.sun.source.tree.*; |
46 |
import com.sun.source.tree.*; |
48 |
import com.sun.source.tree.Tree.Kind; |
47 |
import com.sun.source.tree.Tree.Kind; |
49 |
import com.sun.source.util.TreePath; |
48 |
import com.sun.source.util.TreePath; |
|
|
49 |
import com.sun.source.util.TreePathScanner; |
50 |
import com.sun.source.util.Trees; |
50 |
import com.sun.source.util.Trees; |
|
|
51 |
import java.io.IOException; |
51 |
import java.util.*; |
52 |
import java.util.*; |
|
|
53 |
import java.util.concurrent.atomic.AtomicBoolean; |
54 |
import java.util.logging.Level; |
52 |
import java.util.logging.Logger; |
55 |
import java.util.logging.Logger; |
53 |
import javax.lang.model.element.*; |
56 |
import javax.lang.model.element.*; |
54 |
import javax.lang.model.type.TypeMirror; |
57 |
import javax.lang.model.type.TypeMirror; |
55 |
import javax.lang.model.util.ElementFilter; |
58 |
import javax.lang.model.util.ElementFilter; |
56 |
import org.netbeans.api.java.lexer.JavaTokenId; |
59 |
import org.netbeans.api.java.lexer.JavaTokenId; |
|
|
60 |
import org.netbeans.api.java.source.ClasspathInfo.PathKind; |
57 |
import org.netbeans.api.java.source.CompilationController; |
61 |
import org.netbeans.api.java.source.CompilationController; |
58 |
import org.netbeans.api.java.source.ElementUtilities; |
62 |
import org.netbeans.api.java.source.ElementUtilities; |
|
|
63 |
import org.netbeans.api.java.source.JavaSource; |
59 |
import org.netbeans.api.lexer.Token; |
64 |
import org.netbeans.api.lexer.Token; |
60 |
import org.netbeans.api.lexer.TokenSequence; |
65 |
import org.netbeans.api.lexer.TokenSequence; |
|
|
66 |
import org.netbeans.modules.refactoring.java.RefactoringUtils; |
67 |
import org.netbeans.modules.refactoring.java.WhereUsedElement; |
68 |
import org.netbeans.modules.refactoring.java.spi.JavaWhereUsedFilters; |
69 |
import org.netbeans.modules.refactoring.java.spi.ToPhaseException; |
70 |
import org.openide.ErrorManager; |
71 |
import org.openide.util.Exceptions; |
61 |
|
72 |
|
62 |
/** |
73 |
/** |
63 |
* |
74 |
* |
64 |
* @author Jan Becicka |
75 |
* @author Jan Becicka |
65 |
*/ |
76 |
*/ |
66 |
public class FindUsagesVisitor extends FindVisitor { |
77 |
public class FindUsagesVisitor extends TreePathScanner<Tree, Element> { |
67 |
|
78 |
|
|
|
79 |
private Collection<TreePath> usages = new ArrayList<TreePath>(); |
80 |
private Collection<WhereUsedElement> elements = new ArrayList<WhereUsedElement>(); |
81 |
protected CompilationController workingCopy; |
82 |
private Collection<UsageInComment> usagesInComments = Collections.<UsageInComment>emptyList(); |
68 |
private boolean findInComments = false; |
83 |
private boolean findInComments = false; |
69 |
private Collection<UsageInComment> usagesInComments = Collections.<UsageInComment>emptyList(); |
84 |
private final boolean fromTestRoot; |
|
|
85 |
private final AtomicBoolean inImport; |
86 |
|
70 |
public FindUsagesVisitor(CompilationController workingCopy) { |
87 |
public FindUsagesVisitor(CompilationController workingCopy) { |
71 |
super(workingCopy); |
88 |
this(workingCopy, false); |
|
|
89 |
} |
90 |
|
91 |
public FindUsagesVisitor(CompilationController workingCopy, boolean findInComments) { |
92 |
this(workingCopy, findInComments, RefactoringUtils.isFromTestRoot(workingCopy.getFileObject(), workingCopy.getClasspathInfo().getClassPath(PathKind.SOURCE)), new AtomicBoolean()); |
72 |
} |
93 |
} |
73 |
|
94 |
|
74 |
public Collection<UsageInComment> getUsagesInComments() { |
95 |
public FindUsagesVisitor(CompilationController workingCopy, boolean findInComments, boolean fromTestRoot, AtomicBoolean inImport) { |
75 |
return usagesInComments; |
96 |
try { |
76 |
} |
97 |
setWorkingCopy(workingCopy); |
77 |
|
98 |
} catch (ToPhaseException ex) { |
78 |
public FindUsagesVisitor(CompilationController workingCopy, boolean findInComments) { |
99 |
Exceptions.printStackTrace(ex); |
79 |
super(workingCopy); |
100 |
} |
80 |
this.findInComments = findInComments; |
101 |
this.findInComments = findInComments; |
81 |
if (findInComments) { |
102 |
if (findInComments) { |
82 |
usagesInComments = new ArrayList<UsageInComment>(); |
103 |
usagesInComments = new ArrayList<UsageInComment>(); |
83 |
} |
104 |
} |
|
|
105 |
this.fromTestRoot = fromTestRoot; |
106 |
this.inImport = inImport; |
84 |
} |
107 |
} |
85 |
|
108 |
|
|
|
109 |
//<editor-fold defaultstate="collapsed" desc="Find in Comments"> |
86 |
@Override |
110 |
@Override |
87 |
public Tree visitCompilationUnit(CompilationUnitTree node, Element p) { |
111 |
public Tree visitCompilationUnit(CompilationUnitTree node, Element p) { |
88 |
if (findInComments) { |
112 |
if (findInComments) { |
89 |
String originalName = p.getSimpleName().toString(); |
113 |
String originalName = p.getSimpleName().toString(); |
90 |
TokenSequence<JavaTokenId> ts = workingCopy.getTokenHierarchy().tokenSequence(JavaTokenId.language()); |
114 |
TokenSequence<JavaTokenId> ts = workingCopy.getTokenHierarchy().tokenSequence(JavaTokenId.language()); |
91 |
|
115 |
|
92 |
while (ts.moveNext()) { |
116 |
while (ts.moveNext()) { |
93 |
Token t = ts.token(); |
117 |
Token t = ts.token(); |
94 |
|
118 |
|
95 |
if (t.id() == JavaTokenId.BLOCK_COMMENT || t.id() == JavaTokenId.LINE_COMMENT || t.id() == JavaTokenId.JAVADOC_COMMENT) { |
119 |
if (t.id() == JavaTokenId.BLOCK_COMMENT || t.id() == JavaTokenId.LINE_COMMENT || t.id() == JavaTokenId.JAVADOC_COMMENT) { |
96 |
Scanner tokenizer = new Scanner(t.text().toString()); |
120 |
Scanner tokenizer = new Scanner(t.text().toString()); |
97 |
tokenizer.useDelimiter("[^a-zA-Z0-9_]"); //NOI18N |
121 |
tokenizer.useDelimiter("[^a-zA-Z0-9_]"); //NOI18N |
98 |
|
122 |
|
99 |
while (tokenizer.hasNext()) { |
123 |
while (tokenizer.hasNext()) { |
100 |
String current = tokenizer.next(); |
124 |
String current = tokenizer.next(); |
101 |
if (current.equals(originalName)) { |
125 |
if (current.equals(originalName)) { |
Lines 107-149
Link Here
|
107 |
} |
131 |
} |
108 |
return super.visitCompilationUnit(node, p); |
132 |
return super.visitCompilationUnit(node, p); |
109 |
} |
133 |
} |
|
|
134 |
//</editor-fold> |
110 |
|
135 |
|
111 |
@Override |
|
|
112 |
public Tree visitIdentifier(IdentifierTree node, Element p) { |
113 |
addIfMatch(getCurrentPath(), node, p); |
114 |
return super.visitIdentifier(node, p); |
115 |
} |
116 |
|
117 |
@Override |
118 |
public Tree visitMemberSelect(MemberSelectTree node, Element p) { |
119 |
addIfMatch(getCurrentPath(), node,p); |
120 |
return super.visitMemberSelect(node, p); |
121 |
} |
122 |
|
123 |
@Override |
124 |
public Tree visitNewClass(NewClassTree node, Element p) { |
125 |
Trees trees = workingCopy.getTrees(); |
126 |
ClassTree classTree = ((NewClassTree) node).getClassBody(); |
127 |
if (classTree != null && p.getKind()==ElementKind.CONSTRUCTOR) { |
128 |
Element anonClass = workingCopy.getTrees().getElement(TreePath.getPath(workingCopy.getCompilationUnit(), classTree)); |
129 |
if (anonClass==null) { |
130 |
Logger.getLogger("org.netbeans.modules.refactoring.java").severe("FindUsages cannot resolve " + classTree); |
131 |
} else { |
132 |
for (ExecutableElement c : ElementFilter.constructorsIn(anonClass.getEnclosedElements())) { |
133 |
MethodTree t = workingCopy.getTrees().getTree(c); |
134 |
TreePath superCall = trees.getPath(workingCopy.getCompilationUnit(), ((ExpressionStatementTree) t.getBody().getStatements().get(0)).getExpression()); |
135 |
Element superCallElement = trees.getElement(superCall); |
136 |
if (superCallElement != null && superCallElement.equals(p) && !workingCopy.getTreeUtilities().isSynthetic(superCall)) { |
137 |
addUsage(superCall); |
138 |
} |
139 |
} |
140 |
} |
141 |
} else { |
142 |
addIfMatch(getCurrentPath(), node, p); |
143 |
} |
144 |
return super.visitNewClass(node, p); |
145 |
} |
146 |
|
147 |
private void addIfMatch(TreePath path, Tree tree, Element elementToFind) { |
136 |
private void addIfMatch(TreePath path, Tree tree, Element elementToFind) { |
148 |
if (workingCopy.getTreeUtilities().isSynthetic(path)) { |
137 |
if (workingCopy.getTreeUtilities().isSynthetic(path)) { |
149 |
if (ElementKind.CONSTRUCTOR != elementToFind.getKind() |
138 |
if (ElementKind.CONSTRUCTOR != elementToFind.getKind() |
Lines 158-164
Link Here
|
158 |
if (el == null) { |
147 |
if (el == null) { |
159 |
path = path.getParentPath(); |
148 |
path = path.getParentPath(); |
160 |
if (path != null && path.getLeaf().getKind() == Kind.IMPORT) { |
149 |
if (path != null && path.getLeaf().getKind() == Kind.IMPORT) { |
161 |
ImportTree impTree = (ImportTree)path.getLeaf(); |
150 |
ImportTree impTree = (ImportTree) path.getLeaf(); |
162 |
if (!impTree.isStatic()) { |
151 |
if (!impTree.isStatic()) { |
163 |
return; |
152 |
return; |
164 |
} |
153 |
} |
Lines 176-182
Link Here
|
176 |
if (el == null) { |
165 |
if (el == null) { |
177 |
return; |
166 |
return; |
178 |
} |
167 |
} |
179 |
Iterator iter = workingCopy.getElementUtilities().getMembers(el.asType(),new ElementUtilities.ElementAcceptor() { |
168 |
Iterator iter = workingCopy.getElementUtilities().getMembers(el.asType(), new ElementUtilities.ElementAcceptor() { |
180 |
@Override |
169 |
@Override |
181 |
public boolean accept(Element e, TypeMirror type) { |
170 |
public boolean accept(Element e, TypeMirror type) { |
182 |
return id.equals(e.getSimpleName()); |
171 |
return id.equals(e.getSimpleName()); |
Lines 192-213
Link Here
|
192 |
return; |
181 |
return; |
193 |
} |
182 |
} |
194 |
} |
183 |
} |
195 |
if (elementToFind!=null&& elementToFind.getKind() == ElementKind.METHOD && el.getKind() == ElementKind.METHOD) { |
184 |
if (elementToFind != null && elementToFind.getKind() == ElementKind.METHOD && el.getKind() == ElementKind.METHOD) { |
196 |
if (el.equals(elementToFind) || workingCopy.getElements().overrides((ExecutableElement) el, (ExecutableElement) elementToFind, (TypeElement) elementToFind.getEnclosingElement())) { |
185 |
if (el.equals(elementToFind) || workingCopy.getElements().overrides((ExecutableElement) el, (ExecutableElement) elementToFind, (TypeElement) elementToFind.getEnclosingElement())) { |
197 |
addUsage(getCurrentPath()); |
186 |
addUsage(path); |
198 |
} |
187 |
} |
199 |
} else if (el.equals(elementToFind)) { |
188 |
} else if (el.equals(elementToFind)) { |
200 |
addUsage(getCurrentPath()); |
189 |
final ElementKind kind = elementToFind.getKind(); |
|
|
190 |
if(kind.isField() || kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.RESOURCE_VARIABLE) { |
191 |
JavaWhereUsedFilters.ReadWrite access = JavaWhereUsedFilters.ReadWrite.READ; |
192 |
TreePath parentPath = path.getParentPath(); |
193 |
Tree parentTree = parentPath.getLeaf(); |
194 |
Kind parentKind = parentTree.getKind(); |
195 |
|
196 |
switch(parentKind) { |
197 |
case ARRAY_ACCESS: |
198 |
case MEMBER_SELECT: |
199 |
// TODO: Check usages of arrays for writing |
200 |
break; |
201 |
|
202 |
case POSTFIX_INCREMENT: |
203 |
case POSTFIX_DECREMENT: |
204 |
case PREFIX_INCREMENT: |
205 |
case PREFIX_DECREMENT: |
206 |
access = JavaWhereUsedFilters.ReadWrite.READ_WRITE; |
207 |
break; |
208 |
|
209 |
case ASSIGNMENT: { |
210 |
AssignmentTree assignmentTree = (AssignmentTree) parentTree; |
211 |
ExpressionTree left = assignmentTree.getVariable(); |
212 |
if (left.equals(tree)) { |
213 |
access = JavaWhereUsedFilters.ReadWrite.WRITE; |
214 |
} |
215 |
break; |
216 |
} |
217 |
case MULTIPLY_ASSIGNMENT: |
218 |
case DIVIDE_ASSIGNMENT: |
219 |
case REMAINDER_ASSIGNMENT: |
220 |
case PLUS_ASSIGNMENT: |
221 |
case MINUS_ASSIGNMENT: |
222 |
case LEFT_SHIFT_ASSIGNMENT: |
223 |
case RIGHT_SHIFT_ASSIGNMENT: |
224 |
case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT: |
225 |
case AND_ASSIGNMENT: |
226 |
case XOR_ASSIGNMENT: |
227 |
case OR_ASSIGNMENT: { |
228 |
CompoundAssignmentTree compoundAssignmentTree = (CompoundAssignmentTree) parentTree; |
229 |
ExpressionTree left = compoundAssignmentTree.getVariable(); |
230 |
if (left.equals(tree)) { |
231 |
access = JavaWhereUsedFilters.ReadWrite.READ_WRITE; |
232 |
} |
233 |
break; |
234 |
} |
235 |
} |
236 |
addUsage(path, access); |
237 |
} else { |
238 |
addUsage(path); |
239 |
} |
201 |
} |
240 |
} |
202 |
} |
241 |
} |
|
|
242 |
|
243 |
/** |
244 |
* |
245 |
* @param workingCopy |
246 |
* @throws org.netbeans.modules.refactoring.java.spi.ToPhaseException |
247 |
*/ |
248 |
public final void setWorkingCopy(CompilationController workingCopy) throws ToPhaseException { |
249 |
this.workingCopy = workingCopy; |
250 |
try { |
251 |
if (this.workingCopy.toPhase(JavaSource.Phase.RESOLVED) != JavaSource.Phase.RESOLVED) { |
252 |
throw new ToPhaseException(); |
253 |
} |
254 |
} catch (IOException ioe) { |
255 |
ErrorManager.getDefault().notify(ioe); |
256 |
} |
257 |
} |
258 |
|
259 |
public Collection<UsageInComment> getUsagesInComments() { |
260 |
return usagesInComments; |
261 |
} |
203 |
|
262 |
|
|
|
263 |
protected void addUsage(TreePath tp, JavaWhereUsedFilters.ReadWrite access) { |
264 |
assert tp != null; |
265 |
elements.add(WhereUsedElement.create(workingCopy, tp, access, fromTestRoot, inImport)); |
266 |
usages.add(tp); |
267 |
} |
268 |
|
269 |
public boolean isInImport() { |
270 |
return inImport.get(); |
271 |
} |
272 |
|
273 |
protected void addUsage(TreePath tp) { |
274 |
assert tp != null; |
275 |
elements.add(WhereUsedElement.create(workingCopy, tp, fromTestRoot, inImport)); |
276 |
usages.add(tp); |
277 |
} |
278 |
|
279 |
public Collection<WhereUsedElement> getElements() { |
280 |
return elements; |
281 |
} |
282 |
|
283 |
public Collection<TreePath> getUsages() { |
284 |
return usages; |
285 |
} |
286 |
|
287 |
@Override |
288 |
public Tree visitIdentifier(IdentifierTree node, Element p) { |
289 |
addIfMatch(getCurrentPath(), node, p); |
290 |
return super.visitIdentifier(node, p); |
291 |
} |
292 |
|
293 |
@Override |
294 |
public Tree visitMemberSelect(MemberSelectTree node, Element p) { |
295 |
addIfMatch(getCurrentPath(), node, p); |
296 |
return super.visitMemberSelect(node, p); |
297 |
} |
298 |
|
299 |
@Override |
300 |
public Tree visitNewClass(NewClassTree node, Element p) { |
301 |
Trees trees = workingCopy.getTrees(); |
302 |
ClassTree classTree = ((NewClassTree) node).getClassBody(); |
303 |
if (classTree != null && p.getKind() == ElementKind.CONSTRUCTOR) { |
304 |
Element anonClass = workingCopy.getTrees().getElement(TreePath.getPath(workingCopy.getCompilationUnit(), classTree)); |
305 |
if (anonClass == null) { |
306 |
Logger.getLogger("org.netbeans.modules.refactoring.java").log(Level.SEVERE, "FindUsages cannot resolve {0}", classTree); // NOI18N |
307 |
} else { |
308 |
for (ExecutableElement c : ElementFilter.constructorsIn(anonClass.getEnclosedElements())) { |
309 |
MethodTree t = workingCopy.getTrees().getTree(c); |
310 |
TreePath superCall = trees.getPath(workingCopy.getCompilationUnit(), ((ExpressionStatementTree) t.getBody().getStatements().get(0)).getExpression()); |
311 |
Element superCallElement = trees.getElement(superCall); |
312 |
if (superCallElement != null && superCallElement.equals(p) && !workingCopy.getTreeUtilities().isSynthetic(superCall)) { |
313 |
addUsage(superCall); |
314 |
} |
315 |
} |
316 |
} |
317 |
} else { |
318 |
addIfMatch(getCurrentPath(), node, p); |
319 |
} |
320 |
return super.visitNewClass(node, p); |
321 |
} |
322 |
|
204 |
public static class UsageInComment { |
323 |
public static class UsageInComment { |
|
|
324 |
|
205 |
int from; |
325 |
int from; |
206 |
int to; |
326 |
int to; |
|
|
327 |
|
207 |
public UsageInComment(int from, int to) { |
328 |
public UsageInComment(int from, int to) { |
208 |
this.from = from; |
329 |
this.from = from; |
209 |
this.to = to; |
330 |
this.to = to; |
210 |
} |
331 |
} |
211 |
} |
332 |
} |
212 |
} |
333 |
} |
213 |
|
|
|