001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * Portions Copyrighted 2007 Sun Microsystems, Inc.
027: */
028: package org.netbeans.modules.refactoring.java.api;
029:
030: import com.sun.source.tree.MemberSelectTree;
031: import com.sun.source.tree.Tree;
032: import com.sun.source.util.TreePath;
033: import com.sun.source.util.TreePathScanner;
034: import java.io.IOException;
035: import java.util.ArrayList;
036: import java.util.Collection;
037: import java.util.EnumSet;
038: import java.util.HashSet;
039: import java.util.List;
040: import java.util.Set;
041: import javax.lang.model.element.Element;
042: import javax.lang.model.element.ElementKind;
043: import javax.lang.model.element.ExecutableElement;
044: import javax.lang.model.element.TypeElement;
045: import javax.lang.model.type.TypeMirror;
046: import javax.lang.model.util.Types;
047: import org.netbeans.api.java.source.CancellableTask;
048: import org.netbeans.api.java.source.ClassIndex.SearchKind;
049: import org.netbeans.api.java.source.ClassIndex.SearchScope;
050: import org.netbeans.api.java.source.ClasspathInfo;
051: import org.netbeans.api.java.source.CompilationController;
052: import org.netbeans.api.java.source.CompilationInfo;
053: import org.netbeans.api.java.source.ElementHandle;
054: import org.netbeans.api.java.source.JavaSource;
055: import org.netbeans.api.java.source.JavaSource.Phase;
056: import org.netbeans.api.java.source.SourceUtils;
057: import org.netbeans.api.java.source.TreePathHandle;
058: import org.netbeans.api.java.source.TypeMirrorHandle;
059: import org.netbeans.modules.refactoring.java.RetoucheUtils;
060: import org.netbeans.modules.refactoring.java.ui.tree.ElementGripFactory;
061: import org.openide.filesystems.FileObject;
062:
063: /**
064: *
065: * @author Tim Boudreau
066: * @author Jan Becicka
067: */
068: public final class JavaRefactoringUtils {
069: private JavaRefactoringUtils() {
070: }
071:
072: /**
073: * @param method
074: * @param info
075: * @return collection of ExecutableElements which are overidden by 'method'
076: */
077: public static Collection<ExecutableElement> getOverriddenMethods(
078: ExecutableElement method, CompilationInfo info) {
079: return RetoucheUtils.getOverridenMethods(method, info);
080: }
081:
082: /**
083: * @param method
084: * @param info
085: * @return collection of ExecutableElements which overrides 'method'
086: */
087: public static Collection<ExecutableElement> getOverridingMethods(
088: ExecutableElement method, CompilationInfo info) {
089: return RetoucheUtils.getOverridingMethods(method, info);
090: }
091:
092: /**
093: * Returns true if file is on known source path.
094: *
095: * @param fo
096: * @return
097: */
098: public static boolean isOnSourceClasspath(FileObject fo) {
099: return RetoucheUtils.isOnSourceClasspath(fo);
100: }
101:
102: /**
103: * returns true if file's mime type is text/x-java and file is on know source path
104: * @param file
105: * @return
106: */
107: public static boolean isRefactorable(FileObject file) {
108: return RetoucheUtils.isRefactorable(file) && file.canWrite()
109: && file.canRead();
110: }
111:
112: /**
113: * Returns all supertypes of given type.
114: * @param type
115: * @param info
116: * @param sourceOnly library classes ignored if true
117: * @return
118: */
119: public static Collection<TypeElement> getSuperTypes(
120: TypeElement type, CompilationInfo info, boolean sourceOnly) {
121: return RetoucheUtils.getSuperTypes(type, info);
122: }
123:
124: /**
125: * Finds the nearest enclosing ClassTree on <code>path</code> that
126: * is class or interface or enum or annotation type and is or is not annonymous.
127: * In case no ClassTree is found the first top level ClassTree is returned.
128: *
129: * Especially useful for selecting proper tree to refactor.
130: *
131: * @param javac javac
132: * @param path path to search
133: * @param isClass stop on class
134: * @param isInterface stop on interface
135: * @param isEnum stop on enum
136: * @param isAnnotation stop on annotation type
137: * @param isAnonymous check if class or interface is annonymous
138: * @return path to the enclosing ClassTree
139: */
140: public static TreePath findEnclosingClass(CompilationInfo javac,
141: TreePath path, boolean isClass, boolean isInterface,
142: boolean isEnum, boolean isAnnotation, boolean isAnonymous) {
143: return RetoucheUtils.findEnclosingClass(javac, path, isClass,
144: isInterface, isEnum, isAnnotation, isAnonymous);
145: }
146:
147: public static List<TypeMirror> elementsToTypes(
148: List<? extends Element> typeParams) {
149: return RetoucheUtils.resolveTypeParamsAsTypes(typeParams);
150: }
151:
152: // /**
153: // * Finds type parameters from <code>typeArgs</code> list that are referenced
154: // * by <code>tm</code> type.
155: // * @param utils compilation type utils
156: // * @param typeArgs modifiable list of type parameters to search; found types will be removed (performance reasons).
157: // * @param result modifiable list that will contain referenced type parameters
158: // * @param tm parametrized type to analyze
159: // */
160: // public static void findUsedGenericTypes(Types utils, List<TypeMirror> typeArgs, List<TypeMirror> result, TypeMirror tm) {
161: // RetoucheUtils.findUsedGenericTypes(utils, typeArgs, result, tm);
162: // }
163:
164: public static ClasspathInfo getClasspathInfoFor(FileObject... files) {
165: return RetoucheUtils.getClasspathInfoFor(files);
166: }
167:
168: //From here down is useful stuff from contrib/refactorings
169:
170: public static List<TreePathHandle> treesToHandles(TreePath parent,
171: Iterable<? extends Tree> trees, CompilationInfo info) {
172: List<TreePathHandle> result = new ArrayList<TreePathHandle>(
173: trees instanceof Collection ? ((Collection) trees)
174: .size() : 11);
175: for (Tree tree : trees) {
176: TreePath path = TreePath.getPath(parent, tree);
177: TreePathHandle handle = TreePathHandle.create(path, info);
178: result.add(handle);
179: assert handle.resolve(info) != null : "Newly created TreePathHandle resolves to null"; //NOI18N
180: assert handle.resolve(info).getLeaf() != null : "Newly created TreePathHandle.getLeaf() resolves to null"; //NOI18N
181: }
182: return result;
183: }
184:
185: /**
186: * Convert Trees to TreePathHandles
187: * @param trees
188: * @param info
189: * @return
190: */
191: public static List<TreePathHandle> treesToHandles(
192: Iterable<? extends Tree> trees, CompilationInfo info) {
193: List<TreePathHandle> result = new ArrayList<TreePathHandle>(
194: trees instanceof Collection ? ((Collection) trees)
195: .size() : 11);
196: for (Tree tree : trees) {
197: TreePath path = TreePath.getPath(info.getCompilationUnit(),
198: tree);
199: if (path == null) {
200: throw new IllegalArgumentException(tree
201: + " does not belong to " + //NOI18N
202: "the same compilation unit passed to this method"); //NOI18N
203: }
204: TreePathHandle handle = TreePathHandle.create(path, info);
205: result.add(handle);
206: assert handle.resolve(info) != null : "Newly created TreePathHandle resolves to null"; //NOI18N
207: assert handle.resolve(info).getLeaf() != null : "Newly created TreePathHandle.getLeaf() resolves to null"; //NOI18N
208: }
209: return result;
210: }
211:
212: /**
213: * Resolves ElementHandles to Elemnts
214: * @param handles
215: * @param info
216: * @return
217: */
218: public static <T extends Element> List<T> handlesToElements(
219: Iterable<ElementHandle<T>> handles, CompilationInfo info) {
220: List<T> result = new ArrayList<T>(
221: handles instanceof Collection ? ((Collection) handles)
222: .size() : 0);
223: for (ElementHandle<? extends T> h : handles) {
224: T element = h.resolve(info);
225: assert element != null : element + " resolves to null"; //NOI18N
226: result.add(element);
227: }
228: return result;
229: }
230:
231: /**
232: * Resolves TypeMirrorHandles to TypeMirrors
233: * @param types
234: * @param info
235: * @return
236: */
237: public static List<TypeMirror> handlesToTypes(
238: Iterable<? extends TypeMirrorHandle> types,
239: CompilationInfo info) {
240: List<TypeMirror> result = new ArrayList<TypeMirror>();
241: for (TypeMirrorHandle h : types) {
242: result.add(h.resolve(info));
243: }
244: return result;
245: }
246:
247: /**
248: * Creates TypeMirrosHandles from TypeMirrors
249: * @param types
250: * @return
251: */
252: public static List<TypeMirrorHandle> typesToHandles(
253: Iterable<? extends TypeMirror> types) {
254: List<TypeMirrorHandle> result = new ArrayList<TypeMirrorHandle>();
255: for (TypeMirror h : types) {
256: result.add(TypeMirrorHandle.create(h));
257: }
258: return result;
259: }
260:
261: /**
262: * Create ElementHandles from Elements
263: * @param elements
264: * @return
265: */
266: public static <T extends Element> List<ElementHandle<T>> elementsToHandles(
267: Iterable<? extends T> elements) {
268: List<ElementHandle<T>> result = new ArrayList<ElementHandle<T>>(
269: elements instanceof Collection ? ((Collection) elements)
270: .size()
271: : 11);
272: for (T element : elements) {
273: ElementHandle<T> handle = ElementHandle.<T> create(element);
274: assert handle != null : "Couldn't create handle for "
275: + element; //NOI18N
276: result.add(handle);
277: }
278: return result;
279: }
280:
281: /**
282: *
283: * @param e
284: * @param wc
285: * @return
286: * @throws java.io.IOException
287: */
288: public static Collection<TreePathHandle> getInvocationsOf(
289: ElementHandle e, CompilationController wc)
290: throws IOException {
291: assert e != null;
292: assert wc != null;
293: wc.toPhase(Phase.RESOLVED);
294: Element element = e.resolve(wc);
295: TypeElement type = wc.getElementUtilities()
296: .enclosingTypeElement(element);
297: ElementHandle<TypeElement> elh = ElementHandle
298: .<TypeElement> create(type);
299: assert elh != null;
300: //XXX do I want the enclosing type element for elh here?
301: Set<ElementHandle<TypeElement>> classes = wc
302: .getClasspathInfo()
303: .getClassIndex()
304: .getElements(
305: elh,
306: EnumSet
307: .<SearchKind> of(SearchKind.METHOD_REFERENCES),
308: EnumSet.<SearchScope> of(SearchScope.SOURCE));
309: List<TreePathHandle> result = new ArrayList<TreePathHandle>();
310: for (ElementHandle<TypeElement> h : classes) {
311: result.addAll(getReferencesToMember(h, wc
312: .getClasspathInfo(), e));
313: }
314: return result;
315: }
316:
317: /**
318: * Get all of the references to the given member element (which may be part of another type) on
319: * the passed element.
320: * @param on A type which presumably refers to the passed element
321: * @param toFind An element, presumably a field or method, of some type (not necessarily the passed one)
322: */
323: public static Collection<TreePathHandle> getReferencesToMember(
324: ElementHandle<TypeElement> on, ClasspathInfo info,
325: ElementHandle toFind) throws IOException {
326: FileObject ob = SourceUtils.getFile(on, info);
327: assert ob != null : "SourceUtils.getFile(" + on
328: + ") returned null"; //NOI18N
329: JavaSource src = JavaSource.forFileObject(ob);
330: InvocationScanner scanner = new InvocationScanner(toFind);
331: src.runUserActionTask(scanner, true);
332: return scanner.usages;
333: }
334:
335: private static final class InvocationScanner extends
336: TreePathScanner<Tree, ElementHandle> implements
337: CancellableTask<CompilationController> {
338: private CompilationController cc;
339: private final ElementHandle toFind;
340:
341: InvocationScanner(ElementHandle toFind) {
342: this .toFind = toFind;
343: }
344:
345: @Override
346: public Tree visitMemberSelect(MemberSelectTree node,
347: ElementHandle p) {
348: assert cc != null;
349: Element e = p.resolve(cc);
350: addIfMatch(getCurrentPath(), node, e);
351: return super .visitMemberSelect(node, p);
352: }
353:
354: private void addIfMatch(TreePath path, Tree tree,
355: Element elementToFind) {
356: if (cc.getTreeUtilities().isSynthetic(path))
357: return;
358:
359: Element el = cc.getTrees().getElement(path);
360: if (el == null)
361: return;
362:
363: if (elementToFind.getKind() == ElementKind.METHOD
364: && el.getKind() == ElementKind.METHOD) {
365: if (el.equals(elementToFind)
366: || cc.getElements().overrides(
367: ((ExecutableElement) el),
368: (ExecutableElement) elementToFind,
369: (TypeElement) elementToFind
370: .getEnclosingElement())) {
371: addUsage(getCurrentPath());
372: }
373: } else if (el.equals(elementToFind)) {
374: addUsage(getCurrentPath());
375: }
376: }
377:
378: Set<TreePathHandle> usages = new HashSet<TreePathHandle>();
379:
380: void addUsage(TreePath path) {
381: usages.add(TreePathHandle.create(path, cc));
382: }
383:
384: boolean cancelled;
385:
386: public void cancel() {
387: cancelled = true;
388: }
389:
390: public void run(CompilationController cc) throws Exception {
391: if (cancelled)
392: return;
393: cc.toPhase(Phase.RESOLVED);
394: if (cancelled)
395: return;
396: this .cc = cc;
397: try {
398: TreePath path = new TreePath(cc.getCompilationUnit());
399: scan(path, toFind);
400: } finally {
401: this .cc = null;
402: }
403: }
404: }
405:
406: public static void cacheTreePathInfo(TreePath tp,
407: CompilationInfo info) {
408: ElementGripFactory.getDefault().put(info.getFileObject(), tp,
409: info);
410: }
411:
412: }
|